Showing posts with label Microsoft Dynamics CRM. Show all posts
Showing posts with label Microsoft Dynamics CRM. Show all posts

Saturday, April 14, 2012

MS CRM4: Retrieving and parsing articles from CRM

We had some articles in CRM that was created on specific template for the purpose of displaying on public web site as bilingual FAQs.

The article template had 4 sections, 2 sections for English question and answer in English, and the other 2 sections for Arabic.

            List<kbarticle> results = new List<kbarticle>();

CrmService crmService = ServiceAssembly.GetCrmService();

QueryExpression query = new QueryExpression();
query.EntityName = "kbarticle";
query.ColumnSet = new ColumnSet(attributes);

query.Criteria.AddCondition(new ConditionExpression("statecode", ConditionOperator.Equal, KbArticleState.Published.ToString()));
query.Criteria.AddCondition(new ConditionExpression("kbarticletemplateid", ConditionOperator.Equal, _articleTemplate));
query.AddOrder("createdon", OrderType.Descending);

int count = 0;
foreach (kbarticle article in crmService.RetrieveMultiple(query).BusinessEntities)
{
count++;
results.Add(article);
if (count >= 5)
break;
}


First I retrieved the templates using the template ID that I created specifically for this purpose



now we have the results, we need to parse article xml for each article



                // We need to return back the question and the answer, whilst preserving
// the formatting of the actual answer.
// In addition, the correct language must be displayed (not both language types).

// Example string in contents:
// <articledata><section id='0'><content><![CDATA[test question english]]></content></section><section id='1'>
// <content><![CDATA[<P align=center>test answer english</P> <UL> <LI> <DIV align=center>Hello</DIV></LI>
// <LI> <DIV align=center>test</DIV></LI> <LI> <DIV align=center>test</DIV></LI></UL> <OL> <LI>Oh</LI>
// <LI>Dear</LI> <LI>My <FONT color=#ff0000><STRONG>ha ha ha</STRONG></FONT></LI></OL>]]></content>
// </section><section id='2'><content><![CDATA[<P align=center>السؤيبليب</P> <P align=center>&nbsp;يبليبلي سليبسليبللا</P>]]></content></section>
// <section id='3'><content><![CDATA[]]></content></section></articledata>

int questionSection = 0;
int answerSection = 1;

if (langugageCode == Lang.ARABIC)
{
questionSection = 2;
answerSection = 3;
}

// Load the article
XmlDocument x = new XmlDocument();
x.LoadXml(articleXML);

// Fetch the question
XmlNode node = x.SelectSingleNode("/articledata/section[@id='" + questionSection + "']/content");

// Question retrieval
string question = node.InnerText;
Tracer.WriteLine("question is: " + question);

// Fetch the answer
node = x.SelectSingleNode("/articledata/section[@id='" + answerSection + "']/content");

// Answer retrieval
string answer = node.InnerText;
Tracer.WriteLine("answer is: " + answer);

// Finally, set the Article class
parsedArticle.Question = question;
parsedArticle.Answer = answer;
parsedArticle.Language = langugageCode;
parsedArticle.ArticleID = articleID;


where parsedArticle is an object that holds the details that we are interested in.

Monday, February 13, 2012

MS CRM4: Editing read only or hidden fields set by JS on the fly

we had a CRM form with some fields set as read-only by JavaScript, we wanted to edit one of these fields, and the form was published to production
Screenshot-2012-02-13_14.39.22
The normal way to edit it is to comment the javascript then edit the field then uncomment it back
We thought of another way, using multi edit feature, created another dummy record, then selected both records, and from more actions select Edit
Screenshot-2012-02-13_14.37.26
The form will be opened, nut non of the javascript will be executed, so all fields will be displayed in normal mode, read only and hidden fields can be edited
Screenshot-2012-02-13_14.37.41
Then you will be able to update the record without any change in customizations.
Don’t forget to delete the dummy record Winking smile

Wednesday, June 1, 2011

CRM4: inserting data field from custom field in related entity depending on the contact language

We faced a situation where we had some data fields in a phone call template, but we wanted to use custom field for this data field depending on the language of the contact, also we had some picklist that is always coming in the user context language, and we wanted it to depend on the contact language
To solve this, I have updated the template with some text pattern for each field, for the picklist and the custom fields, then I have created a plugin for the phone call, with the below steps
1- Get the contact language
2- Get the custom field depending on the language
3- Get the localized picklist label for the language
4- Search the phone call description for patterns, and replace with the localized value
5- Update the phone call with the new description
To get the localized lookup label I used the metadata service to get all pick list values, then compared each picklist option with the value and the language
                        Option[] deptOptions = RetrieveEntityPicklistValues(metaService, EntityName.incident.ToString(), _attCaseInternalStatus);
                        foreach (Option option in deptOptions)
                        {
                            if (option.Value.Value == (int)internalStatus)
                            {
                                foreach (LocLabel label in option.Label.LocLabels)
                                {
                                    if (label.LanguageCode.Value == languageCode)
                                    {
                                        newCaseInternalStatus = label.Label;
                                        break;
                                    }
                                }
                                break;

                            }
                        }


        public Option[] RetrieveEntityPicklistValues(IMetadataService metaService, string strEntityType, string pickListName)
        {
            try
            {
                RetrieveAttributeRequest request = new RetrieveAttributeRequest();
                request.EntityLogicalName = strEntityType;
                request.RetrieveAsIfPublished = true;
                request.LogicalName = pickListName;

                RetrieveAttributeResponse response = (RetrieveAttributeResponse)metaService.Execute(request);
                AttributeMetadata retreivedAttributeMetadata = response.AttributeMetadata;
                if (retreivedAttributeMetadata is PicklistAttributeMetadata)
                {
                    return ((PicklistAttributeMetadata)retreivedAttributeMetadata).Options;
                }
            }
            catch (Exception eGlobalException)
            {
                throw;
            }
            return null;
        }


Same concept can be applied with any template, a more generic solution could be developed by creating a plugin on template retrieval that replaces the values for any retrieved template

Monday, May 23, 2011

Viewstate is not maintained in iframe inside MS CRM form

We had a page that is hosted inside CRM form, the page contains list with a checkboxes beside each each row. When clicking apply, certain action should be performed on the selected items. things are working fine on the development machine, but when hosting inside the CRM form, when clicking “apply”, the action wasn’t applied on the selected items, we discovered later that the code that loops over the checked items, doesn’t run as if there is no records checked.
Doing some search I found that CRM web.config by default has the following line
enableViewState="false" i.e. by default Viewstate is not enabled in CRM.
Changing this to enableViewState="true" and restarting IIS, every thing worked fine and actions were applied successfully.
There is another option which is to enable this in the page directives like the following
<%@ Page Language="C#" ... EnableViewState="true" %>

Thursday, April 28, 2011

Modifying non customizable entities in CRM 4.0

We wanted to add extra columns for the Queues view, while the Queue item is not customizable entity we found a way posted in several blogs, by modifying the "isCustomizable" setting from the DB directly with the below statement

UPDATE Entity
SET ISCUSTOMIZABLE = 1
WHERE NAME = 'queueitem'

After doing this, we were able to open the Queue Item entity and modify the View, we added more columns, then with javascript we modified the values for this columns.

It is very important to change back the settings as it was after finishing the modification by running the same script again and setting it back to 0


UPDATE Entity
SET ISCUSTOMIZABLE = 0
WHERE NAME = 'queueitem'




Wednesday, September 8, 2010

MS CRM Plugin development best practices

While i was debugging, I noticed that update plugin was lots of times, and each time it was called all case properties was sent in the context, While not all of them are updated. so i started searching on how to make sure that only the updated property is sent to the update plugin.
I found this article which is very useful
http://blogs.inetium.com/blogs/azimmer/archive/2010/01/25/plugin-best-practices-in-crm-4-0.aspx

In summary what i was doing wrong is like the following:
- I was doing retrieve entity then after, i was doing update to that entity, while the correct thing is that to do update without doing retrieve.
- When retrieving for any other reason, i was getting all columns, the correct thing to do is to get the desired columns only

Sunday, August 22, 2010

MS CRM passing parameters in the query string

By default MS CRM 4 doesn't accept passing parameters in the query string, and it gives CRM error message
To enable passing parameters
follow the instructions in this URL
http://blogs.msdn.com/b/rextang/archive/2008/09/24/8962549.aspx

by adding a DWORD registry key under MSCRM named DisableParameterFilter and setting the value to 1

Thursday, August 19, 2010

MS CRM Changing business unit for a user gives an error

We were trying to change the business unit for a user and it was giving us CRM error.

We already have increased the timeout long time ago by adding the registry keys as instructed here http://support.microsoft.com/kb/918609

Still having the same error.

Lastly we tried cleaning up the Async table as instructed here http://support.microsoft.com/kb/968520

After doing this we were able to change the business unit for the users

Monday, May 31, 2010

MS CRM4: Creating View and setting filter criteria programmatically

We wanted to create a view with criteria on the “Due Date” field to show all records that have due date on or before today

Checking the view creation wizard, we can select on or before and we must specify specific date, we can’t specify  it as “Today”

Screenshot-2012-02-08_17.03.15

I have came up with a workaround for this, I have created the view and set the criteria to specific date, 01/01/1999 for example, any date. Then I created a plugin to work on execute message, on pre-event, then in the plugin I was parsing the FetchXML of the execution, if the primary entity is same as the view entity, and there is a condition on “Due Date” and the value is “01/01/1999” then to change this value to today’s date in the FetchXML.

main code snippets

//get FetchXML from the context
fetchXml = (string)context.InputParameters.Properties["FetchXml"];

//get the entity name
string entity = xmlDoc.SelectSingleNode("fetch/entity").Attributes["name"].Value.ToString();

if (entity == "incident") // here I am using incident, replace with your entity name
{

if (xmlDoc.SelectSingleNode("fetch/entity/filter") != null)
{

// Check if there are conditions exists
if (xmlDoc.SelectSingleNode("fetch/entity/filter/condition") != null)
{
// Loop through the conditions to look for the followup by condition
nodes = xmlDoc.SelectNodes("fetch/entity/filter/condition");
foreach (XmlNode node in nodes)
{
if (node.Attributes["attribute"] != null && node.Attributes["operator"] != null && node.Attributes["value"] != null)
{
string slaOnOrBefore = "01/01/1999";
if (node.Attributes["attribute"].Value.ToString().ToLower() == "followupby".ToLower() && node.Attributes["operator"].Value.ToString().ToLower() == "on-or-before".ToLower() && node.Attributes["value"].Value.ToString().ToLower() == slaOnOrBefore.ToLower())
{
node.Attributes[
"value"].Value = DateTime.Today.AddDays(-1).ToString("yyyy-MM-ddT00:00:00");
}
}
}
}
}

//Update the fetch xml
fetchXml = xmlDoc.InnerXml.ToString();
context.InputParameters.Properties[
"FetchXml"] = fetchXml;