Friday, October 30, 2009

Publishing Microsoft CRM 4.0 through ISA Server 2006

by Danny Varghese 02.21.09

Here is a great article that illustrates how to publish Microsoft CRM 4.0 through ISA Server 2006: http://blogs.technet.com/isablog/archive/2008/07/23/publishing-microsoft-crm-4-0-through-isa-server-2006.aspx

The article is broken up into the following sections:

  1. Adjusting CRM Server For External Publishing
    1. General Considerations
    2. IFD Configuraiton
  1. Configuring ISA Server 2006 Web publishing rule
  2. Troubleshooting Tips

For those who need some information on Microsoft ISA Server: http://en.wikipedia.org/wiki/ISA_Server

Rules To Better Microsoft CRM & SSRS

by Danny Varghese 02.21.09

Below are some very useful links on standards for Microsoft CRM and SQL Server Reporting Services:

http://www.ssw.com.au/ssw/Standards/Rules/RulestoBetterMicrosoftCRM.aspx

http://www.ssw.com.au/ssw/Standards/Rules/RulesToBetterSQLReportingServices.aspx

Enjoy!

Example of Dynamic Entity Retrieval

by Danny Varghese 01.31.09


There have been numerous requests on other blogs about sample code to on how to retrieve entities in CRM. One way is to use the CRM web service to retrieve business entities, however by doing so, you're only limited to out-of-the-box entities with system attributes. To retrieve anything more "dynamic," you'll have to employ other methods.  Please remember that in order to retrieve any record, you must have the proper permissions on that entity.

Below is a code example of how to retrieve a record with an id using dynamic entity retrieve:

 






   1: public DynamicEntity RetrieveEntity()
   2: {
   3: //variable initialization
   4: TargetRetrieveDynamic target = new TargetRetrieveDynamic();
   5: RetrieveRequest retrieveRequest = new RetrieveRequest();
   6: RetrieveResponse retrieveResponse = null;
   7: DynamicEntity entity = null;
   8: target.EntityName = <name of entity here>
   9: target.EntityId = <id of entity here>
  10: //initialize request parameters
  11: retrieveRequest.ColumnSet = new AllColumns();
  12: retrieveRequest.ReturnDynamicEntities = true;
  13: retrieveRequest.Target = target;
  14: //build the response object
  15: retrieveResponse = 
  16: (RetrieveResponse)GetCrmService().Execute(retrieveRequest);
  17: //retrieve the service order item from the response
  18: entity = (DynamicEntity)retrieveResponse.BusinessEntity;
  19: return entity;
  20: }
 

The above example is a simple one, but the example below retrieves all contacts that have an account id = some id, and also retrieve the records with only a certain attributes. This is probably a more robust example encompassing many retrieval options:



   1:  
   2: private ArrayList RetrieveMultipleContacts(ICrmService crmService, Guid 
   3: parentAccountId) 
   4: { 
   5: //variable initialization 
   6: ConditionExpression condition = new ConditionBLOCKED EXPRESSION; 
   7: FilterExpression filter = new FilterBLOCKED EXPRESSION; 
   8: QueryExpression query = new QueryBLOCKED EXPRESSION; 
   9: RetrieveMultipleRequest request = new RetrieveMultipleRequest(); 
  10: ColumnSet cols = new ColumnSet(); 
  11: RetrieveMultipleResponse response = null; 
  12: ArrayList contacts = new ArrayList(); 
  13: //Set the condition for retrieval 
  14: condition.AttributeName = "parentcustomerid"; 
  15: condition.Operator = ConditionOperator.Equal; 
  16: condition.Values = new string[] { parentAccountId.ToString() }; 
  17: //Set the properties of the filter. 
  18: filter.FilterOperator = LogicalOperator.And; 
  19: filter.AddCondition(condition); 
  20: //Set the attributes needed to be returned. NOTE: The CRM 
  21: Sdk has an erroneous example 
  22: //of how to set the attributes for retrieval. 
  23: cols.Attributes.Add("address1_line1"); 
  24: cols.Attributes.Add("address1_line2"); 
  25: cols.Attributes.Add("address1_line3"); 
  26: cols.Attributes.Add("address1_city"); 
  27: cols.Attributes.Add("address1_stateorprovince"); 
  28: cols.Attributes.Add("address1_postalcode"); 
  29: cols.Attributes.Add("address1_country"); 
  30: cols.Attributes.Add("telephone1"); 
  31: cols.Attributes.Add("fax"); 
  32: //Set the properties of the QueryExpression object. 
  33: query.EntityName = EntityName.contact.ToString(); 
  34: query.ColumnSet = cols; 
  35: query.Criteria = filter; 
  36: //Set the query for the request and set the flag to return 
  37: //dynamic entities 
  38: request.Query = query; 
  39: //retrieve the contacts 
  40: response = (RetrieveMultipleResponse)crmService.Execute(request); 
  41: foreach (BusinessEntity cont in 
  42: response.BusinessEntityCollection.BusinessEntities) 
  43: { 
  44: contacts.Add(cont); 
  45: } 
  46: return contacts; 
  47: } 


I hope these examples help someone, happy coding!

Adding A Filtered Lookup In CRM

by Danny Varghese 02.03.09

Another common question I see in blogs from users are is there a way to add filtered lookups? That is only allow users to "lookup" certain records that related to that particular one. Here's a real life example:

Say you have an account that has a 1:N parental relationship with entity A. Now let's say there's another entity B that has N:1 referential relationships with both account, and entity A. There is a way on entity B so that after you select, on the lookup, a record of the account you want to relate to it, to filter the second lookup of entity A to only those related to the account you just selected. i.e.

Parental Relationship

Account --> Entity A

Referential Relationship

Entity B -- Account

Entity B -- Entity A

With simple JavaScript, when a user selects the lookup value for the account, the lookup for Entity A can be filtered to point to only those entity A's that are related to the account you just chose. Here's the code to place on the form of Entity B:

crmForm.all.<lookup field for entity A>.additionalparams = 'search=' + encodeURIComponent(crmForm.all.<lookup field for account>.DataValue[0].name);

That's it! Simple, yet effective.

Example of Dynamic Entity Retrieval

by Danny Varghese 01.31.09


There have been numerous requests on other blogs about sample code to on how to retrieve entities in CRM. One way is to use the CRM web service to retrieve business entities, however by doing so, you're only limited to out-of-the-box entities with system attributes. To retrieve anything more "dynamic," you'll have to employ other methods.  Please remember that in order to retrieve any record, you must have the proper permissions on that entity.

Below is a code example of how to retrieve a record with an id using dynamic entity retrieve:

 


public DynamicEntity RetrieveEntity()
{
//variable initialization
TargetRetrieveDynamic target = new TargetRetrieveDynamic();
RetrieveRequest retrieveRequest = new RetrieveRequest();
RetrieveResponse retrieveResponse = null;
DynamicEntity entity = null;
target.EntityName = <name of entity here>
target.EntityId = <id of entity here>
//initialize request parameters
retrieveRequest.ColumnSet = new AllColumns();
retrieveRequest.ReturnDynamicEntities = true;
retrieveRequest.Target = target;
//build the response object
retrieveResponse = 
(RetrieveResponse)GetCrmService().Execute(retrieveRequest);
//retrieve the service order item from the response
entity = (DynamicEntity)retrieveResponse.BusinessEntity;
return entity;
}
 

The above example is a simple one, but the example below retrieves all contacts that have an account id = some id, and also retrieve the records with only a certain attributes. This is probably a more robust example encompassing many retrieval options:

private ArrayList RetrieveMultipleContacts(ICrmService crmService, Guid parentAccountId)

{

//variable initialization

ConditionExpression condition = new ConditionBLOCKED EXPRESSION;

FilterExpression filter = new FilterBLOCKED EXPRESSION;

QueryExpression query = new QueryBLOCKED EXPRESSION;

RetrieveMultipleRequest request = new RetrieveMultipleRequest();

ColumnSet cols = new ColumnSet();

RetrieveMultipleResponse response = null;

ArrayList contacts = new ArrayList();

//Set the condition for retrieval

condition.AttributeName = "parentcustomerid";

condition.Operator = ConditionOperator.Equal;

condition.Values = new string[] { parentAccountId.ToString() };

//Set the properties of the filter.

filter.FilterOperator = LogicalOperator.And;

filter.AddCondition(condition);

//Set the attributes needed to be returned. NOTE: The CRM Sdk has an erroneous example

//of how to set the attributes for retrieval.

cols.Attributes.Add("address1_line1");

cols.Attributes.Add("address1_line2");

cols.Attributes.Add("address1_line3");

cols.Attributes.Add("address1_city");

cols.Attributes.Add("address1_stateorprovince");

cols.Attributes.Add("address1_postalcode");

cols.Attributes.Add("address1_country");

cols.Attributes.Add("telephone1");

cols.Attributes.Add("fax");

//Set the properties of the QueryExpression object.

query.EntityName = EntityName.contact.ToString();

query.ColumnSet = cols;

query.Criteria = filter;

//Set the query for the request and set the flag to return

//dynamic entities

request.Query = query;

//retrieve the contacts

response = (RetrieveMultipleResponse)crmService.Execute(request);

foreach (BusinessEntity cont in response.BusinessEntityCollection.BusinessEntities)

{

contacts.Add(cont);

}

return contacts;

}

I hope these examples help someone, happy coding!

Friday, February 27, 2009

Creating a Birthday Contact List

Today we welcome our guest blogger CRM MVP Darren Liu from the Crowe Horwath company.

Have you ever been asked by someone to get a list of contacts having birthdays during a certain time period from CRM? If so what have you done to perform this task? Within the application, birthdays are tracked on Contact records as a single date (including year). This causes problems when searching for birthdays in a certain time period as the birth date is evaluated including the year. To illustrate, consider the following example:

· John Dole, 10/1/1980

· Adam Smith, 9/1/1970

· Mark Francis, 10/10/1960

Within CRM, searching for date is done by range. There is no easy way to identify from the above contacts all those having birthday in October as any range you choose will include the year. Wildcard functions on date fields are not a workable solution.

There are several solutions to this problem including JavaScript to parse birthday on the onChange event, a custom report or a plug-in. The desired functionality is to be able to search by birth month, birth day, and/or birth year, allowing the user to quickly identify all birthdays in a certain time period.

In this blog, I will show you how to use a pre plug-in to parse the birthday field into day, month and year. This way, the users will able to perform searches using Advanced Find. I have chosen the plug-in approach because it will help me parse the birthday field not only when the users update the birthday on the contact form but also when updating the birthday through the CRM web service for data imports and data integration.

Implement the pre plug-in

1. Create New Attributes

Create three new attribute on the Contact entity form in CRM. After creating the new attributes, publish the Contact customization.

Display Name

Schema Name

Type

Searchable

Values

Birth Month

new_birthmonth

Picklist

Yes

Jan = 1, Feb = 2, Mar = 3, Apr = 4, May = 5, Jun = 6, Jul = 7, Aug = 8, Sept = 9, Oct = 10, Nov = 11, Dec = 12

Birth Day

new_birthday

Int

Yes

Min Value = 1

Max Value = 31

Birth Year

new_birthyear

Int

Yes

Min Value = 1900

Max Value = 9999

clip_image002

2. Create pre plug-in using Visual Studio

Create a plug-in project name Crm.Plugin, copy and paste the following code to your Plug-in project.

using System;


using System.Collections.Generic;


using System.Text;


using Microsoft.Crm.Sdk;


using Microsoft.Crm.SdkTypeProxy;


 


namespace Crm.Plugin


{


  public class MonthDayYearContactPlugin : IPlugin


  {


    public void Execute(IPluginExecutionContext context)


    {


    DynamicEntity entity = null;


 


    if (context.InputParameters.Properties.Contains(ParameterName.Target) &&


        context.InputParameters.Properties[ParameterName.Target] is DynamicEntity)


    {


        entity = (DynamicEntity)context.InputParameters[ParameterName.Target];


        if (entity.Name != EntityName.contact.ToString()) { return; }


    }


    else


    {


        return;


    }


 


    try


    {


        if (entity.Properties.Contains("birthdate"))


        {


            CrmDateTime _birthdate = (CrmDateTime)entity["birthdate"];


            if (_birthdate.IsNull)


            {


                entity["new_birthday"] = CrmNumber.Null;


                entity["new_birthmonth"] = Picklist.Null;


                entity["new_birthyear"] = CrmNumber.Null;


            }


            else


            {


                DateTime birthdayValue = _birthdate.UserTime; 


                entity["new_birthday"] = new CrmNumber(birthdayValue.Day);


                entity["new_birthmonth"] = new Picklist(birthdayValue.Month);


                entity["new_birthyear"] = new CrmNumber(birthdayValue.Year);


            }


        }


    }


    catch (Exception ex)


    {


        throw new InvalidPluginExecutionException("An error occurred in the Month, Day, Year Plug-in for Contact.", ex);


    }


    }


  }


}


 




3. Register the plug-in The last step is to register the plug-in. To register the plug-in, you may use the Plug-in Registration tool from the MSDN Code Gallery. After the assembly is uploaded, you need to associate the following steps to the plug-in:





 
























Message: Create


Primary Entity: contact


Filtering Attributes: birthdate


Eventing Pipeline Stage of Execution: Pre Stage


Execution Mode: Synchronous



Triggering Pipeline: Parent Pipeline



Message: Update


Primary Entity: contact


Filtering Attribute: birthdate


Eventing Pipeline Stage of Execution: Pre Stage


Execution Mode: Synchronous



Triggering Pipeline: Parent Pipeline



Message: Create


Primary Entity: contact


Filtering Attributes: birthdate


Eventing Pipeline Stage of Execution: Pre Stage


Execution Mode: Synchronous



Triggering Pipeline: Child Pipeline



Message: Update


Primary Entity: contact


Filtering Attribute: birthdate


Eventing Pipeline Stage of Execution: Pre Stage


Execution Mode: Synchronous



Triggering Pipeline: Child Pipeline





Summary








That’s all there is to it! The users will now be able to use Advanced Find to quickly identify their contacts birthday in a certain time period from now on. For the existing contacts previously stored in CRM, you will need to write a one-time SQL script to update the birthday fields in the MSCRM database in order for CRM to return the correct data back to the users. Hopefully this will help you on your next CRM project.



clip_image004



clip_image006



Cheers,



Darren Liu



Published Friday, February 27, 2009 9:26 AM by crmblog

Report on Opportunities Lost to Competitors

There is an out-of-the box relationship between competitors and opportunities in CRM that allows you to track many competitors to any one opportunity.  However, when you close an opportunity as lost to a competitor, you may select one specific competitor within the Close Opportunity window.  This is a different relationship in CRM than competitor to opportunities.

image

What if you want an all-up view of all your lost opportunities showing the competitors that you lost to?

When trying to get this report, many people naturally turn to advanced find views (AFVs) to try to create a query for this data.  This approach won’t return all the data you need in an all-up Lost Opportunity report with Competitors because you cannot create an AFV on the Opportunity Close Activity.  The closest you can get with AFV is to look for Activities, filter the Activity Type = Opportunity Close, and filter Competitor = [fill in the blank]. 

image

This only works when filtering one competitor because you cannot display a column for Competitor in this view – there is a 1:N relationship between Activity and Opportunity Close.

Thus, the way to get this view of your data is to create a Report (Workplace –> Reports)using the report wizard.  The report wizard differs from AFV in that it allows you to JOIN data from different data tables (entities) rather than be restricted to lookup fields in 1:N relationships between data tables (entities).  Here’s how to do it:

Go to Workplace –> Reports –> Report Wizard:

image

Name the report and specify primary and related record types:

image

Set a filter to return all activities = opportunity close (like I mentioned with the AFV), and Opportunity Close Competitor “contains data”:

image

Lay out fields in your report.  In this example I’ve included Est. Revenue on the related Opportunity so you can quantify exactly how much revenue was lost to the competitor.  You can summarize by this amount in your report in order to create a chart in the next step:

image image

Add a chart if you want to:

image image

Final Report:

image

With pie chart or bar chart:

image image

Enjoy.

Posted: Monday, February 16, 2009 10:37 PM by Laura Robinson