Archives for category: CRM
I recently encountered a situation in which one of our CRM users wanted to clean up some old CRM Views which were created using Advanced Find and shared with him by someone who is no longer with the company.
This presented an interesting dilemma, because the person who shared the views did not give the CRM users delete permissions, so when he attempted to delete the saved view, he would get an Access Denied error.
And even though I was the CRM Administrator, I could not see the view because it was not shared with me. The fix turned out to be easy, but I thought I would share it since it is not exactly intuitive.
In order to fix this issue, I had to click on Settings -> Administration -> Users, select Disabled Users and locate the previous employee’s disabled CRM record. I double clicked on the record to view the detail and clicked on the Reassign Records toolbar item. I choose to reassign the user’s records to me.
Once I had done that, I could click on Advanced Find and choose Saved Views. I was then able to go in and delete the Saved Views which were created by the previous employee.
Advertisements

I recently upgraded to Microsoft CRM 2013. Now every time I launch the application, I am presented with the dreaded “Pending email warning” dialog: You have email messages more than 24 hours old that haven’t been sent. To send these messages, sign in to Microsoft Dynamics CRM Online for Outlook, or verify with your system administrator that server-side synchronization or the Email Router is setup to send messages for you. For more information about email configuration, see online Help.

Apparently, this popup is occurring because the email router has not been setup. In order to prevent this message from occurring, we will need to configure the email router to send emails via some transport other than the user’s Outlook.

It would be annoying if it happened just the first time a user opened the application, but the fact that it pops up EVERY TIME I launch CRM is a potential support nightmare.

Thankfully, there is an easy way (other than configuring the email router) to remove the annoying dialog, and that is by adding a registry setting. As always, proceed WITH CAUTION and perform any necessary backups before attempting to edit your registry settings.

Here are the steps:

  • Choose Windows Start and select File -> Run -> Regedit

  • Traverse to the Microsoft CRM registry settings location: HKEY_LOCAL_MACHINE -> SOFTWARE -> Microsoft -> MSCRM
  • Check to make sure the registry key DisablePendingEmailReminder has not already been created. If it hasn’t, then create the following new registry key:
    • Right-click -> New
    • DWORD (32-bit value)
    • Name it DisablePendingEmailReminder
    • Give it a value of 1

  • The setting for me worked immediately and thankfully did not require a reboot or IISRESET

You guess it, they are not compatible. When I try to load our CRM 2011 application in my IE 11 browser, it attempts to load the mobile web page.

That’s because the Microsoft team decided that it might be a good idea to change the User Agent string in IE 11. I disagree.

There are two workarounds for this issue, other than using Chrome or upgrading to CRM 2013 (yes, it is fixeddoes not appear to be an issue in this version).

  1. Use the full CRM URL, including the main.aspx page, i.e. http://crm.mycompany.com/mycrmcompanyname/main.aspx
  2. Run your CRM web site in compatibility mode. (This is a good idea if you’re also running SharePoint 2013 sites. Yes, there are issues.)

To run IE 11 in compatibility mode, follow these steps:

  1. Choose ALT-T
  2. Click Compatibility View Settings
  3. Add the current site to your compatibility view
  4. Choose OK

I ran into an odd problem today. I am upgrading our on-premise CRM environment to CRM 2013. I have some client-side code that uses the OrganizationData.svc to fetch some data from a related Opportunity entity, as follows:

}

function PopulateOpportunityData(oppId){

var ODataHost = location.protocol + ‘//’ + location.host + ‘/’ + Xrm.Page.context.getOrgUniqueName();

var ODataService = “/XRMServices/2011/OrganizationData.svc”;

var ODataQuery = “/OpportunitySet?$select=EstimatedCloseDate,Description&$filter=OpportunityId eq guid’” + oppId.toString() + “’”;

var ODataURL = ODataHost + ODataService + ODataQuery;

$.ajax({

type: “GET”,

contentType: “application/json; charset=utf-8”,

datatype: “json”,

url: ODataURL,

beforeSend: function (XMLHttpRequest) {

XMLHttpRequest.setRequestHeader(“Accept”, “application/json”);

},

success: function (data, textStatus, XmlHttpRequest) {

alert(“OData Execution Success”);

},

error: function (XmlHttpRequest, textStatus, errorObject) {

alert(“OData Execution Error Occurred”);

}

});

}

This works just fine over HTTP, but our company is implementing CRM over SSL/HTTPS only. When I run the page using HTTPS, I get the following error: Not Found.

In fact when I paste the OData Query URL into my web browser, it gives me the same error.

But over HTTP, it resolves just fine.

I looked at my IIS configuration and noticed that my HTTPS binding did not contain a host name.

But when I tried to modify it, the host name field was disabled.

I did some more research and discovered that there is an appcmd that will allow you to specify the host name from the command line:

You will need to run CMD as an Administrator and paste in the following command:

C:\Windows\System32\Inetsrv\appcmd set site /site.name:”Microsoft Dynamics CRM” /bindings.[protocol=’https’,bindingInformation=’*:443:’].bindingInformation:*:443:crm.yourhostname.com

Microsoft Dynamics CRM refers the name of the web site.

crm.yourhostname.com refers to your host name.

After I run the command, I notice that my host name is correctly set for the HTTPS binding.

Make sure you do an IISRESET.

And if that doesn’t work, then remove the HTTP binding and readd it and then do another IISRESET.

The result? J

I have a custom entity form in CRM. When the user selects an opportunity, I want to populate the form data with values from the selected opportunity.

I quickly realize that I cannot use the CRM Business Rules functionality for this, because it does not currently support setting field values from related entity data. So I decide to use a client-side OData query to handle this functionality and am learning a lot about how to handle certain OData field types.

My OData query looks like this:
function PopulateOpportunityData(oppId) {
var ODataHost = location.protocol + ‘//’ + location.host + ‘/’ + Xrm.Page.context.getOrgUniqueName();
var ODataService = “/XRMServices/2011/OrganizationData.svc”;
var ODataQuery = “/OpportunitySet?$select=EstimatedCloseDate,CustomerId,Cat_RevenueMonths,Description&$filter=OpportunityId eq guid’” + oppId.toString() + “’”;
var ODataURL = ODataHost + ODataService + ODataQuery;
$.ajax({
type: “GET”,
contentType: “application/json; charset=utf-8”,
datatype: “json”,
url: ODataURL,
beforeSend: function (XMLHttpRequest) {
XMLHttpRequest.setRequestHeader(“Accept”, “application/json”);
},
success: function (data, textStatus, XmlHttpRequest) {
var opp = data.d.results;
if (opp == null || opp.length == 0) {
return;
}
var endDate = null;
var projectMonths = HandleODataInt(opp[0].Cat_RevenueMonths);
projectMonths = projectMonths == null ? 1 : projectMonths;
var startDate = HandleODataDate(opp[0].EstimatedCloseDate);
if (startDate != null) {
Xrm.Page.getAttribute(“cat_startdate”).setValue(startDate);
endDate = startDate.addMonths(projectMonths);
Xrm.Page.getAttribute(“cat_enddate”).setValue(endDate);
}
var account = opp[0].CustomerId;
if (account != null) {
Xrm.Page.getAttribute(“cat_account”).setValue([{ id: account.Id, name: account.Name, entityType: account.LogicalName }]);
}
},
error: function (XmlHttpRequest, textStatus, errorObject) {
     var errorCode = 1;
}
});
}

The first thing I notice about the date field is that it comes back looking something like this: “/Date(1385704800000)/”, which is not entirely intuitive.

With dates, you have to strip away the extra stuff, convert the number to an integer value, and then pass it into a new date function, like this:

function HandleODataDate(dateValue) {

var returnValue = null;

try

{

dateValue = dateValue == null ? “” : dateValue.toString();

if (dateValue != “”) {

dateValue = dateValue.replace(“/”, “”);

dateValue = dateValue.replace(“Date(“, “”);

dateValue = dateValue.replace(“)”, “”);

dateValue = dateValue.replace(“/”, “”);

var returnValue = new Date(parseInt(dateValue));

returnValue = isNaN(returnValue) ? null : returnValue;

}

}

catch (Exception) { }

return returnValue;

}

And then “/Date(1385704800000)/” becomes this:

I have a custom entity form in CRM. When the user selects an opportunity, I want to populate the form data with values from the selected opportunity.

One of the fields I want to populate is the Account field with the Account entity that is related to the selected Opportunity.

My OData query looks like this:

function PopulateOpportunityData(oppId) {

var ODataHost = location.protocol + ‘//’ + location.host + ‘/’ + Xrm.Page.context.getOrgUniqueName();

var ODataService = “/XRMServices/2011/OrganizationData.svc”;

var ODataQuery = “/OpportunitySet?$select=EstimatedCloseDate,CustomerId,Cat_RevenueMonths,Description&$filter=OpportunityId eq guid’” + oppId.toString() + “’”;

var ODataURL = ODataHost + ODataService + ODataQuery;

$.ajax({

type: “GET”,

contentType: “application/json; charset=utf-8”,

datatype: “json”,

url: ODataURL,

beforeSend: function (XMLHttpRequest) {

XMLHttpRequest.setRequestHeader(“Accept”, “application/json”);

},

success: function (data, textStatus, XmlHttpRequest) {

var opp = data.d.results;

if (opp == null || opp.length == 0) {

return;

}

var endDate = null;

var projectMonths = HandleODataInt(opp[0].Cat_RevenueMonths);

projectMonths = projectMonths == null ? 1 : projectMonths;

var startDate = HandleODataDate(opp[0].EstimatedCloseDate);

if (startDate != null) {

Xrm.Page.getAttribute(“cat_startdate”).setValue(startDate);

endDate = startDate.addMonths(projectMonths);

Xrm.Page.getAttribute(“cat_enddate”).setValue(endDate);

}

var account = opp[0].CustomerId;

if (account != null) {

Xrm.Page.getAttribute(“cat_account”).setValue([{ id: account.Id, name: account.Name, entityType: account.LogicalName }]);

}

},

error: function (XmlHttpRequest, textStatus, errorObject) {

var errorCode = 1;

}

});

}

When an Opportunity is selected, I get an Account object back:

var account = opp[0].CustomerId;

I want to set my field entitled “cat_account” to this lookup value. This is how you do it in CRM 2011 or CRM 2013:

Xrm.Page.getAttribute(“cat_account”).setValue([{ id: account.Id, name: account.Name, entityType: account.LogicalName }]);

I have created a custom entity entitled “Funding Request”. I want to add a field that allows users to select multiple products from a list. My first thought is to go into the Fields interface and create a new Pick List and look for the option that allows users to choose multiple items, but the option is not there. It is there in SharePoint, but for some reason it is not here in CRM. CRM 2013 and still no multiple selection list. What?!

So instead, I have to use this infuriating workaround. Hrrmph…

  1. Create a custom entity for your list.
  2. Create an N:N relationship between your list entity and your main entity, i.e. in my case my list entity is “Products Used” and my main entity is “Funding Request”.
  3. Populate List Entity.
  4. Go to your main entity form and add the list entity as a Sub-Grid.

Okay. Let’s do this…

Create List Entity

  • Navigate to CRM -> Settings -> Customization
  • Select Entities and choose New.
  • In this example, I created an entity for my list called “Products Used“, not to be confused with the CRM Entity “Product”.
  • Select an area to display your entity in so that you can add values. In this case I choose “Settings” so that my list entity does not appear in the main navigation.
  • Under Communication & Collaboration, I unchecked everything, because this is meant to be used only as a select list.
  • You may want to change the “Display Name” of the Name field for this list to better represent the list entity you are creating, i.e. I renamed mine to “Product Name“. You can do this by clicking on Fields and double-clicking the Name field.
  • Please Note: You will need to Publish this customization before you can add items to the list

Create N:N Relationship between Main Entity and List Entity

  • Navigate to CRM -> Settings -> Customization.
  • Expand Entities.
  • Locate your new List Entity (“Products Used” in my case) and expand it.
  • Select N:N Relationships and choose New Many-to-Many Relationship.
  • Set Current Entity to your Entity List (in my case “Products Used”) and Other Entity to your Main Entity (in my case “Funding Request”).

Populate List Entity

  • Once you have published your customizations, you can populate your List Entity with the values you want in your multi-select list.
  • In this case, I went to CRM -> Settings and selected Products Used.
  • Then I added a new item for each list item.

Add the List Entity to Main Entity Form as a Sub Grid

  • Navigate to CRM -> Settings -> Customization.
  • Expand Entities.
  • Locate your new Main Entity (in my case “Funding Request”) and expand it.
  • Select Forms and choose Main.
  • Click the Insert Tab and choose Sub-Grid.

  • A Set Properties dialog will display. First, change the Entity to your Custom List entity (in my case “Products Used”).
  • Set the default view. I defaulted mine to “Active Products Used”.
  • If you want them to have the option of changing the view, then turn View Select to “On”. I left mine “Off”, because I only want them selecting from Active Products.
  • If your list is long, you can select “Display Search Box” to allow the user to search for a specific item.

  • You can click the formatting tab to determine how many columns the Sub-Grid spans.

  • Choose Set when you are finished.

Don’t forget to publish your customizations. J

The result? Yes, it did seem like more work than necessary.

I ran into this issue when I was generating emails as part of a workflow process. It would create the email task, but none of them would actually send and when I looked at the task, it would say “This message has not yet been submitted for delivery” at the top of the task in a yellow bar. No explanation, no nothing.

The first thing I did was make sure that the CRM email router was configured accurately on the CRM server.

FIRST, I had my EMAIL-OUT configuration setup against our corporate SMTP server.

SECOND, I applied my EMAIL-OUT configuration to my CRM instance.

THIRD, I tested my EMAIL-OUT configuration.

FOURTH, I manually created an email task and made sure it sent successfully.

That’s what helped me to realize that the issue was with the emails being generated by my workflow. It turns out that there is a little “bug/feature” in the CRM system. When you create an email task in a workflow process, you have to make sure that you specify a value for No. Delivery Attempts. If you don’t, the subsequent value will be NULL, and the email router will ignore it. Therefore, the email will never be sent.

It doesn’t really matter what value you set in there. The email router will recognize anything 0 or greater. If you put 0, it still sends.

For those of us who have had the unfortunate experience of trying to access CRM data using SOAP queries, it is a luxury to be able to query CRM entities using LINQ.

It is pretty easy to setup your .NET project to use CRM and LINQ. Simply install the CRM SDK. This link is to the CRM 2013 SDK, but you can certainly do this in CRM 2011 as well:
http://www.microsoft.com/en-us/download/details.aspx?id=40321

Once you have extracted the CRM SDK, you can use the CrmSvcUtil command line function to generate an xrm.cs file to include in your project, which generates the CRM entity definitions.
http://msdn.microsoft.com/en-us/library/ff681563.aspx

  1. Open the Command Prompt as an Administrator.
  2. Change directories to the SDK directory which contains the CrmSvcUtil executable.

cd c:\CRM-2013-SDK\SDK\Bin

  1. Type the CrmSvcUtil.exe command with the following parameters:
    1. /out – [name of the file you want generated]
    2. /url – [link to the organization service of your CRM implementation]
    3. /domain – [domain name of the CRM administrator account you will use to generate the file]
    4. /username – [user name of the CRM administrator account you will use to generate the file]
    5. /password – [password of the CRM administrator account you will use to generate the file]

CrmSvcUtil.exe /codeCustomization:”Microsoft.Xrm.Client.CodeGeneration.CodeCustomization, Microsoft.Xrm.Client.CodeGeneration” /out:Xrm.cs /url:https://crm.mycrmserver.com/myorganization/XRMServices/2011/Organization.svc /domain:mydomain /username:mycrmadministrator /password:mycrmadminpassword /namespace:Xrm /serviceContextName:XrmServiceContext

Once the xrm.cs file has been generated, you can include it as a class in your .Net project. Then you can create a context object:

private void RefreshContext()

{

if (context != null)

{

context.Dispose();

}

ClientCredentials credentials = new ClientCredentials();

credentials.UserName.UserName = MscrmWebService.LoginName;

credentials.UserName.Password = MscrmWebService.Password;

string link = isDev ? MscrmWebService.LinkDev : MscrmWebService.Link;

Uri organizationUri = new Uri(MscrmWebService.Link);

Uri homeRealmUri = null;

using (serviceProxy = new OrganizationServiceProxy(organizationUri, homeRealmUri, credentials, null))

{

serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());

service = (IOrganizationService)serviceProxy;

context = new XrmServiceContext(service);

}

}

And from there you can query the CRM entities like you would any other LINQ entity. Some examples include:

Retrieve CRM Contact by Id

public Contact RetrieveContact(Guid contactId)

{

RefreshContext();

return context.ContactSet.Where(e => e.ContactId == contactId).Single();

}

 

Retrieve CRM Contact by Name

public Contact RetrieveContact(string firstName, string lastName)

{

RefreshContext();

return context.ContactSet.Where(e => e.FirstName == firstName && e.LastName == lastName).Single();

}

 

Retrieve CRM Account by Id

public Account RetrieveAccount(Guid accountId)

{

RefreshContext();

return context.AccountSet.Where(e => e.AccountId == accountId).Single();

}

Retrieve CRM Active Accounts

public IQueryable<Account> RetrieveActiveAccounts()

{

return

context.AccountSet.Where(

e =>

(e.CustomerTypeCode.Value == (int)ContactType.Customer ||

e.CustomerTypeCode.Value == (int)ContactType.Prospect) && e.StateCode == (int)StateCode.Active)

.OrderBy(e => e.Name);

}

Retrieve CRM Accounts Last Modified

public List<Account> RetrieveLastModifiedAccounts(int recordLastModifiedDays, bool activeOnly, ref bool isError, ref string errorDetails)

{

System.DateTime today = System.DateTime.Today;

if (recordLastModifiedDays > 0)

{

today = today.AddDays(recordLastModifiedDays * -1);

}

if (activeOnly)

{

return context.AccountSet.Where(e => e.StateCode == (int)StateCode.Active && e.ModifiedOn.Value >= new DateTime(today.Year, today.Month, today.Day)).OrderBy(e => e.Name).ToList();

}

return context.AccountSet.Where(e => e.ModifiedOn.Value >= new DateTime(today.Year, today.Month, today.Day)).OrderBy(e => e.Name).ToList();

}

 

Retrieve CRM Contacts Last Modified

public List<Contact> RetrieveLastModifiedContacts(int recordLastModifiedDays, bool activeOnly, ref bool isError, ref string errorDetails)

{

System.DateTime today = System.DateTime.Today;

if (recordLastModifiedDays > 0)

{

today = today.AddDays(recordLastModifiedDays * -1);

}

if (activeOnly)

{

return context.ContactSet.Where(e => e.StateCode == (int)StateCode.Active && e.ModifiedOn.Value >= new DateTime(today.Year, today.Month, today.Day)).OrderBy(e => e.FullName).ToList();

}

return context.ContactSet.Where(e => e.ModifiedOn.Value >= new DateTime(today.Year, today.Month, today.Day)).OrderBy(e => e.FullName).ToList();

}

 

Retrieve CRM Opportunities Last Modified

public List<Opportunity> RetrieveLastModifiedOpportunities(int recordLastModifiedDays, bool activeOnly, ref bool isError, ref string errorDetails)

{

System.DateTime today = System.DateTime.Today;

if (recordLastModifiedDays > 0)

{

today = today.AddDays(recordLastModifiedDays * -1);

}

if (activeOnly)

{

return context.OpportunitySet.Where(e => e.StateCode == (int)OpportunityState.Open && e.ModifiedOn.Value >= new DateTime(today.Year, today.Month, today.Day)).OrderBy(e => e.Name).ToList();

}

return context.OpportunitySet.Where(e => e.ModifiedOn.Value >= new DateTime(today.Year, today.Month, today.Day)).OrderBy(e => e.Name).ToList();

}

 

Retrieve CRM Opportunities by Status

public List<Opportunity> RetrieveLastModifiedOpportunitiesByStatus(int status, int recordLastModifiedDays, ref bool isError, ref string errorDetails)

{

System.DateTime today = System.DateTime.Today;

if (recordLastModifiedDays > 0)

{

today = today.AddDays(recordLastModifiedDays * -1);

}

return context.OpportunitySet.Where(e => e.StateCode == status && e.ModifiedOn.Value >= new DateTime(today.Year, today.Month, today.Day)).OrderBy(e => e.Name).ToList();

}

 

public List<Opportunity> RetrieveOpportunitiesByStatus(int status, ref bool isError, ref string errorDetails)

{

return context.OpportunitySet.Where(e => e.StateCode == status).OrderBy(e => e.Name).ToList();

}

In CRM, I have a field that allows the user to select from a set of Picklist values.  One of the values is no longer active.  I did not want to delete the Picklist value and lose historical data, but I did not want users to be able to select that value for new Opportunities.  This functionality is very easy to apply on the client-side of the CRM form.

In the following example, the “Form_onload” function is wired up to the CRM form onload event.

function Form_onload() {
HandleBusinessUnitValues();
}

function HandleBusinesUnitValues() {
try {
// Check to see if the value we want to remove is the value that is currently selected.
// We will only remove the value from the picklist if it is not selected.
var wdc = ‘8’;
var currentValue = Xrm.Page.getAttribute(“crm_picklist_field_name”).getValue();
currentValue = currentValue == null ? ” : currentValue ;
if (currentValue != wdc) {
var pickListField = Xrm.Page.getControl(“crm_picklist_field_name”);
pickListField.removeOption(wdc);
}
}
catch (Exception) { }
}