Saturday, July 18, 2009

CRM 4.0 Setting a Picklist Default Value


Currently Dynamics supports setting default values for two attribute types: PicklistAttributeMetaddata (Picklist) and BooleanAttributeMetadata (bit fields). If you intend to set the default using custom code you need to follow the below process:

1. Retrieve the attribute metadata (unless you’re creating a new one) using RetrieveAttributeRequest
2. Cast the returned AttributeMetadata to a PicklistAttributeMetadata.
3. Set the picklist metadata Default value to an integer of you choice.
4. Update the attribute metadata using UpdateAttribute Request.
5. Publish the changes using PublishXml Request.

The bellow code is a working example which sets the account Relationship Type (customertypecode) picklist to Customer (value = 3).


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Metadata;
using Microsoft.Crm.SdkTypeProxy.Metadata;

namespace GI.Sendbox
{
class Program
{
static void Main(string[] args)
{
try
{
/* Create Authenticatio Token */
CrmAuthenticationToken token = new CrmAuthenticationToken();
token.AuthenticationType = 0;
token.OrganizationName = "MicrosoftCRM";

/* Create a CrmService end point */
CrmService crmService = new CrmService();
crmService.UnsafeAuthenticatedConnectionSharing = true;
crmService.Url = "http://localhost:5555/mscrmservices/2007/crmservice.asmx";
crmService.UseDefaultCredentials = true;
crmService.CrmAuthenticationTokenValue = token;

/* Create a MetadataService end point */
MetadataService metaService = new MetadataService();
metaService.Url = "http://localhost:5555/mscrmservices/2007/metadataservice.asmx";
metaService.UseDefaultCredentials = true;
metaService.UnsafeAuthenticatedConnectionSharing = true;
metaService.CrmAuthenticationTokenValue = token;

/* Retrieve the attribute metadata */
RetrieveAttributeRequest attributeRequest = new RetrieveAttributeRequest();
attributeRequest.EntityLogicalName = "account";
attributeRequest.LogicalName = "customertypecode"; //Relationship Type picklist

RetrieveAttributeResponse attributeResponse =
(RetrieveAttributeResponse)metaService.Execute(attributeRequest);

/* Cast the attribute metadata to a picklist metadata */
PicklistAttributeMetadata picklist =
(PicklistAttributeMetadata)attributeResponse.AttributeMetadata;

/* set the default value to "customer" (3) */
picklist.DefaultValue = (object)3;

/* update the attribute metadata */
UpdateAttributeRequest updateRequest = new UpdateAttributeRequest();
updateRequest.Attribute = picklist;
updateRequest.EntityName = "account";
updateRequest.MergeLabels = false;

metaService.Execute(updateRequest);

/* Publish the changes */
PublishXmlRequest request = new PublishXmlRequest();

request.ParameterXml = @"<importexportxml>
<entities>
<entity>account</entity>
</entities>
<nodes/>
<securityroles/>
<settings/>
<workflows/>
</importexportxml>";


PublishXmlResponse response =
(PublishXmlResponse)crmService.Execute(request);
}
catch(System.Web.Services.Protocols.SoapException sex)
{
Console.WriteLine(sex.Detail.OuterXml);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}

Tuesday, July 14, 2009

CRM 4.0 Logging user login information


Following is a simple example on how-to log a user interaction with CRM. The sample uses a simple plug-in that references the System.Web assembly. Once you create a reference to this assembly you’re able to read the HttpContext and consequently read the information you wish to log.

The plug-in hooks into the execute message which in most cases is the first event to fire (grid event). The plug-in also writes a cookie back to the browser to mark the logging operation so it only happens once while the main crm application is opened.

In the example I also create a simple logInfo entity with fields I’m interested in logging.

Please not that while reading information from the httpcontext and other objects like Request might be considered supported, reading information that CRM uses like httpcontext.items[“organizationName”] or writing information to a cookie might break your support. So when you write values back to the browser make sure you’re using a well defined naming convention that will always stay unique. And instead of reading the orgname from the items collection get it from the request url.


using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using System.Web;

namespace GI.SandBox
{
public class LoginHandler : IPlugin
{
#region IPlugin Members

public void Execute(IPluginExecutionContext context)
{
if (context.MessageName != "Execute")
{
return;
}

if (context.Stage != MessageProcessingStage.BeforeMainOperationOutsideTransaction)
{
return;
}

if (!(context.CallerOrigin is ApplicationOrigin))
{
return;
}

HttpContext webContext = HttpContext.Current;
HttpCookie logInfo = webContext.Request.Cookies.Get("loginfo");

if (logInfo == null)
{
DynamicEntity logInfoEntry = new DynamicEntity();
logInfoEntry.Name = "gi_loginfo";

logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_userhostaddress",
webContext.Request.UserHostAddress
)
);

logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_useridentity",
webContext.User.Identity.Name
)
);

logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_starturl",
webContext.Request.Path
)
);

logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_hostname",
webContext.Request.Url.Host
)
);

if (webContext.Items["organizationName"] != null)
{
logInfoEntry.Properties.Add
(
new StringProperty
(
"gi_userhostaddress",
webContext.Items["organizationName"].ToString()
)
);
}

logInfoEntry.Properties.Add
(
new CrmDateTimeProperty
(
"gi_datetime",
new CrmDateTime(webContext.Timestamp.ToString())
)
);

TargetUpdateDynamic targetRecord = new TargetUpdateDynamic();
targetRecord.Entity = logInfoEntry;

UpdateRequest updateRequest = new UpdateRequest();
updateRequest.Target = targetRecord;

context.CreateCrmService(true).Execute(updateRequest);

logInfo = new HttpCookie("loginfo");
logInfo.Value = DateTime.Now.ToString();
webContext.Response.Cookies.Add(logInfo);
}
}

#endregion
}
}

Sunday, July 12, 2009

CRM 4.0 Cascading wizard




The Cascading wizard is a complementary add-on to dynamic mapping facility. Currently dynamics only supports mapping when a user creates a new child entity within a parent context (form). Knowing that many partners invest quite a bit of energy developing solutions that require cascading and having to deal with these types of requirements ourselves we decided to create a fully featured mapping / cascading wizard that enable us to complete these tasks with just a few clicks.

The CAW wizard has the following features which can save you hours of tedious development.

1.Mapping fields from a parent entity when a child entity is created outside of the parent form. For example: A common requirement might be to inherit account information when you create a new contact from dynamics contacts grid (view). Currently the account fields are only mapped if you create the contact from the account form.

2.Mapping fields from multiple parents. For example: you might have an entity that has lookups to more the 1 entity. When you create the entity you might want to inherit fields from any parent.

3.Cascading parent modifications to all children. For example: you might want to update all contacts under a certain account when the account main phone field (contact business phone) changes.

4.The ability to decide whether to inherit parent attributes only when the child field is empty. For example: you might want to inherit account information when the contact is created but want to enable the user to change the contacts fields afterwards. The CAW wizard enables you to decide whether field changes are cascaded when the child attribute is empty.

5.Cascading drilldown. One of the nicest features of this wizard is that it enables you to drill down the changes from the root entity to the bottom leaf.
For example: if you define an account to contact cascading rules and then define a contact to invoice cascading rule on the same fields. And then change the field on the account form the change is carried out to the invoice entity.

6.The wizard integrates seamlessly with the current mapping facility. And you can choose to utilize both or just use the CAW wizard.

Common CAW features: The wizard supports –
1. Both on-premise and partner hosted environments.
2. IFD – Internet facing deployment
3. 32 and 64 bit servers
4. Multi-Tenancy
5. All Languages
6. All Rollups

We made a video to illustrate the above features.
In order to play back the video, right click on the flash movie then click rewind and play.



If you have question regarding the wizard functionality you can ask them here of send your enquiry to support@gicrm.com

Sunday, July 5, 2009

CRM 4.0 Record Filter Wizard




The idea behind the RFW wizard is to create a security filter in the context of each entity data and user role and expose / grant access to records only when a certain condition is met or under a certain restriction. For example: an organization might want a specific salesperson role to see leads that are connected to a specific product family or allow a low-privileged role to only see accounts that their credit limit is between a certain range.The RFW wizard will always make sure that the returned data is within the security filter parameters.

Another good example that we use is creating a severity or scoring attributes that enables the organization to categorize each entity and then create a security filter that allows users to see data depending on the scoring attribute value.

Actually there is no limit to the type of security filters that you can create. You can construct any filter (simple or complex) using any business logic and utilizing existing or specialized attributes to achieve a high data aware security state.

The security filters are setup using the wizard User Interface without the need to write custom code.

The following demonstration is a simple example of how you can take advantage of the RFW wizard.
The first scenario creates a security restriction on the top business unit (a template) which hides accounts that their credit limit is between 100,000 and 1 million $. This means that all the views, quick create and advance find will adhere to this restriction and only return accounts that meet the security filter.

The second scenario overrides the template and creates a security filter on the system administrator role. This time the filter is setup on the credit hold attribute returning only accounts that their credit is not held.

The last scenario defines a security filter for a specific marketing manager and allows him to only to view accounts that their category is set to standard.

RFW Technical Information:

1.Support for Internet Explorer 8, Internet Facing Deployment - IFD, and all available rollups (1 – 5).
2.Support for all searchable entities (entities that you can search using advanced find)
3.Support for Security Hierarchy i.e. creating business unit templates, overriding the templates for each CRM role and creating specific security filters for users.
4.Supports all views e.g. (public, private , associated , quick find , advanced find , print pages etc)



If you have any questions regarding the RFW wizard post them here or send you enquiry to support@gicrm.com

Wednesday, July 1, 2009

CRM 4.0 Auto Sharing wizard




CRM 4.0 permission mechanism and access level rules can be quite limiting. This is especially true when privacy of data is required, visibility of records depends on business decisions or visibility depends on the source (role or user) which triggered the action. On other occasions you need to control visibility of record across sibling business units and business units that are not under the same branch.

Most customers overcome the problem by granting organization access to roles which needs work with data. Of course this is very problematic and reduces the security to minimum and so they usually start looking for solution like field level security which enables the organization to hide certain entity fields from a specific business unit, role or user.

Dynamics does address this problem using a mechanism called sharing. The problem with the sharing mechanism is that it’s a manual process which shifts the responsibility of sharing to the user. This behavior is rarely acceptable especially because sharing rules needs to adhere to specific business decisions and sharing logic.

I’ve seen some very interesting solutions that use dynamics workflow engine to facilitate the sharing of records. However we needed a comprehensive solution and so we developed the Auto Sharing wizard which addresses most scenarios (all of ours anyway).

Following is a technical description of the Auto Sharing wizard and what it can do for you.

1.Creation of Global Sharing rules - Fired by anyone (We use them as sharing templates and override with specific rules).
a.When the record is created
b.When the record match a specific snapshot (state)

2.Creation of Specific Sharing rules - Fired only when the current user or user role matches the sharing rule source (see video)
a.When the record is created
b.When the record match a specific snapshot (state)

3.Creation of a Sharing hierarchy e.g. Rules setup as global fire first  Rule setup at the Role level may override or add more sharing rules  Rule setup at the User Level overrides the Role level rules and used as Sharing rule exceptions.

4.Creation of Sharing rules that are integrated as a workflow step

Following is a list of scenarios that can be resolved using the wizard

Sharing of record only when a specific Role or User triggers the action
Conditional sharing either by using a snapshot query or by integrating the sharing rule in an “IF” workflow routine.
Sharing Record with lower non privileged business units, roles and users
Sharing Records with sibling Business units and Business unit that are not under the same branch

ASW Presentation – in order to rewind click on the flash movie; then rewind and play.



If you have questions regarding the wizard feel free to ask them here or send them to support@gicrm.com