You are currently browsing the tag archive for the ‘CRM 2011’ tag.

For the sake of standardizing the format for all system postal codes, I have implemented the following script to re-format the user input of postal codes for both US and Canada. The purpose is to take the user’s input, and re-arrange it to follow a standard format.

The comments are self-explanatory.

// Function to format postal code
// for both Canadian and US postal codes
function FormatPostalCode(context)
{
  var oField = context.getEventSource().getValue();
  var sTmp;
 
  if(typeof(oField) != "undefined" && oField != null)
  {
    // check for US ZIP code
    if(oField.match(/^[0-9]{5}$/))
    {
        context.getEventSource().setValue(oField);
        return true;
    }

    // check for Canadian postal code
    sTmp = oField.toUpperCase();
    if (sTmp.match(/^[A-Z][0-9][A-Z][0-9][A-Z][0-9]$/))
    {
        sTmp = sTmp.substr(0,3) + " " + sTmp.substr(3,3);
        context.getEventSource().setValue(sTmp);
        return true;
    }
    if (sTmp.match(/^[A-Z][0-9][A-Z].[0-9][A-Z][0-9]$/))
    {
        context.getEventSource().setValue(sTmp);
        return true;
    }

    // alert("Incorrect ZIP/Postal Code format.");
    // postal code could be any other country, so leave as is
  }
}

Add the function in a Web Resource, and reference it on the postal code’s OnChange event. As the script uses the context, make sure you select the “Pass execution context as first parameter” option.

image

Enjoy!

Advertisements

Integrating CRM Accounts with LinkedIn is a very easy step. I have found numerous examples on doing this by using a Web Resource, but I don’t like the way it displays in a frame. It looks anything but professional.

So I decided there’s got to be a better way of doing this.

First off, I am using the jQuery library, so you will need to add that to your resources. It will make it so much easier to select elements on the page.

I have added an on load function to the account:

function Account_onLoad()
{
    var nvs_AccountName = Xrm.Page.getAttribute("name").getValue();
   
    $("#name").after(function() {
        var script = ‘<script src="
http://platform.linkedin.com/in.js" type="text/javascript"></script>’ +
        ‘<script type="IN/CompanyProfile" data-id="’ + nvs_AccountName +
        ‘" data-format="inline" data-related="false"></script>’;
        return script;
    });
}

I am looking for the Account name, as populated in the Name field, and retrieving the LinkedIn profile based on that. I have re-arranged the form to provide the space for the section that will be inserted right below the Account Name field:

image

In the Form Properties, add your references as below:

image

once you have all that set up, try opening an account, and you will get the following view:

image

No more iFrames, it just looks like it belongs there.

The beauty of this approach is also the fact that, if an account is not found on LinkedIn, no problem, the screen will look like so:

image

NOTE: Please be aware that you will get the following prompt:

image

Add LinkedIn to your browser’s trusted sites. In the Trusted Sites configuration, click on Custom level.

image

Set Display Mixed Content to Enable.

image

This setting can be pushed through a group policy. For more details see KB2625928.

Enjoy!

As you probably know, the Product has a non-sufficient form for most customers. Let’s have a look at the actual form, and see what’s missing:

image

Now, from what we see, the List Price is what is being used in the system calculations as the price to sell. The Standard Cost could be the MSRP, and the Current Cost is the price your company pays for the product, or the total cost to produce. This is minimalistic, so let’s look at a scenario:

Your company ABC Inc. buys products, and installs them for customers (let’s say Doors & Windows). How do we apply the form to this model?

First off, you have MSRP (Standard Cost). To that apply a standard discount percentage (needs to be added custom), to result in your Current Cost. To that you apply a percentage for S&H, and any other necessary fees, resulting in your List Price.

Since we do have the Description section, which includes the Vendor details, I think this was the scenario envisioned.

Otherwise, on to the manufacturing scenario:

Your company XYZ Inc. produces paper weights. Applying the form to this model:

Materials Cost + Labor Cost + Other expenses incurred = Current Cost

Current Cost + X Amount (expressed as % in many cases) = List Price

The Vendor becomes an interesting concept now. Either XYZ Inc. is the vendor, in which case the field becomes irrelevant, or you have multiple vendors/distributors, in which case you add the same product for each vendor, so you can track against vendors.

As I was saying, the Product is an entity where you should spend some time to map it correctly to the business model used.

Starting to customize a CRM without considering all the aspects could potentially force you in a corner when you get to the Product entity customization.

Enjoy!

One way or another, eventually you will get a request to change the default amount calculations as built in CRM. This could be either by adding a tax percentage (after all, all provinces or states use a fixed tax rate expressed as a percentage), or to handle some other kind of discount by a specific category of customers. Another common example is to apply tax at the Opportunity or Quote level rather than doing it for each product line added. After all, who wants to do the same task 10, 15 or even 20 times when you can do it just once?

If the approach is by using JScript, it may seem like a trivial task. Retrieve the values filled in by users, put your formulas in, an voila… almost perfect. Except, some fields do not retrain the value you pushed in. Even though the calculation on the screen looks correct, when you close and save your form, the totals are being re-calculated by the system, and your formulas are ignored.

In order to identify these cases, you can look at the MSDN documentation. Following is a sub-set that should help you with any calculations you need to override on the Opportunity, Quote and Invoice. The URLs are pointing to the original extended documentation on MSDN.

Opportunity

http://msdn.microsoft.com/en-us/library/gg328229.aspx

DisplayName

SchemaName

Type

IsValidForUpdate

Account

AccountId

Lookup

FALSE

Actual Revenue

ActualValue

Money

TRUE

Actual Revenue (Base)

ActualValue_Base

Money

FALSE

Contact

ContactId

Lookup

FALSE

Opportunity Discount Amount

DiscountAmount

Money

TRUE

Opportunity Discount Amount (Base)

DiscountAmount_Base

Money

FALSE

Opportunity Discount (%)

DiscountPercentage

Decimal

TRUE

Est. Revenue

EstimatedValue

Money

TRUE

Est. Revenue (Base)

EstimatedValue_Base

Money

FALSE

Exchange Rate

ExchangeRate

Decimal

FALSE

Freight Amount

FreightAmount

Money

TRUE

Freight Amount (Base)

FreightAmount_Base

Money

FALSE

Revenue

IsRevenueSystemCalculated

Boolean

TRUE

Opportunity

OpportunityId

Uniqueidentifier

FALSE

Price List

PriceLevelId

Lookup

TRUE

Pricing Error

PricingErrorCode

Picklist

TRUE

Total Amount

TotalAmount

Money

FALSE

Total Amount (Base)

TotalAmount_Base

Money

FALSE

Total Pre-Freight Amount

TotalAmountLessFreight

Money

FALSE

Total Pre-Freight Amount (Base)

TotalAmountLessFreight

_Base

Money

FALSE

Total Discount Amount

TotalDiscountAmount

Money

FALSE

Total Discount Amount (Base)

TotalDiscountAmount_Base

Money

FALSE

Total Detail Amount

TotalLineItemAmount

Money

FALSE

Total Detail Amount (Base)

TotalLineItemAmount_Base

Money

FALSE

Total Line Item Discount Amount

TotalLineItemDiscountAmount

Money

FALSE

Total Line Item Discount Amount (Base)

TotalLineItemDiscountAmount

_Base

Money

FALSE

Total Tax

TotalTax

Money

FALSE

Total Tax (Base)

TotalTax_Base

Money

FALSE

Currency

TransactionCurrencyId

Lookup

TRUE

NOTE: On the Opportunity, it may seem misleading, but the Discount (%) and Discount fields work independent of each other. By that I mean that you can add a Discount (%) and a Discount, and they will both be subtracted from Product Totals.

Quote

http://msdn.microsoft.com/en-us/library/gg309335.aspx

DisplayName

SchemaName

Type

IsValidForUpdate

Potential Customer

CustomerId

Customer

TRUE

Quote Discount Amount

DiscountAmount

Money

TRUE

Quote Discount Amount (Base)

DiscountAmount_Base

Money

FALSE

Quote Discount (%)

DiscountPercentage

Decimal

TRUE

Exchange Rate

ExchangeRate

Decimal

FALSE

Freight Amount

FreightAmount

Money

TRUE

Freight Amount (Base)

FreightAmount_Base

Money

FALSE

Name

Name

String

TRUE

Opportunity

OpportunityId

Lookup

TRUE

Payment Terms

PaymentTermsCode

Picklist

TRUE

Price List

PriceLevelId

Lookup

TRUE

Total Amount

TotalAmount

Money

FALSE

Total Amount (Base)

TotalAmount_Base

Money

FALSE

Total Pre-Freight Amount

TotalAmountLessFreight

Money

FALSE

Total Pre-Freight Amount (Base)

TotalAmountLessFreight_Base

Money

FALSE

Total Discount Amount

TotalDiscountAmount

Money

FALSE

Total Discount Amount (Base)

TotalDiscountAmount_Base

Money

FALSE

Total Detail Amount

TotalLineItemAmount

Money

FALSE

Total Detail Amount (Base)

TotalLineItemAmount_Base

Money

FALSE

Total Line Item Discount Amount

TotalLineItemDiscountAmount

Money

FALSE

Total Line Item Discount Amount (Base)

TotalLineItemDiscountAmount

_Base

Money

FALSE

Total Tax

TotalTax

Money

FALSE

Total Tax (Base)

TotalTax_Base

Money

FALSE

Currency

TransactionCurrencyId

Lookup

TRUE

 

Invoice

http://msdn.microsoft.com/en-us/library/gg309547.aspx

DisplayName

SchemaName

Type

IsValidForUpdate

Account

AccountId

Lookup

FALSE

Customer

CustomerId

Customer

TRUE

Invoice Discount Amount

DiscountAmount

Money

TRUE

Invoice Discount Amount (Base)

DiscountAmount_Base

Money

FALSE

Invoice Discount (%)

DiscountPercentage

Decimal

TRUE

Exchange Rate

ExchangeRate

Decimal

FALSE

Freight Amount

FreightAmount

Money

TRUE

Freight Amount (Base)

FreightAmount_Base

Money

FALSE

Invoice

InvoiceId

Uniqueidentifier

FALSE

Invoice ID

InvoiceNumber

String

FALSE

Payment Terms

PaymentTermsCode

Picklist

TRUE

Price List

PriceLevelId

Lookup

TRUE

Pricing Error

PricingErrorCode

Picklist

TRUE

Priority

PriorityCode

Picklist

TRUE

Total Amount

TotalAmount

Money

FALSE

Total Amount (Base)

TotalAmount_Base

Money

FALSE

Total Pre-Freight Amount

TotalAmountLessFreight

Money

FALSE

Total Pre-Freight Amount (Base)

TotalAmountLessFreight

_Base

Money

FALSE

Total Discount Amount

TotalDiscountAmount

Money

FALSE

Total Discount Amount (Base)

TotalDiscountAmount_Base

Money

FALSE

Total Detail Amount

TotalLineItemAmount

Money

FALSE

Total Detail Amount (Base)

TotalLineItemAmount_Base

Money

FALSE

Total Line Item Discount Amount

TotalLineItemDiscountAmount

Money

FALSE

Total Line Item Discount Amount (Base)

TotalLineItemDiscountAmount

_Base

Money

FALSE

Total Tax

TotalTax

Money

FALSE

Total Tax (Base)

TotalTax_Base

Money

FALSE

Currency

TransactionCurrencyId

Lookup

FALSE

 

Of course, you could write a plugin to do this, but if you need a quick and dirty solution, maybe for a presentation, or when going for a more agile approach, JScript is your friend.

Also, you will find that, for some fields, you will end-up hiding the original field, and creating your custom field to store the calculated values. When you do so, do not forget to hide the original and add your custom field in all the related views. The last thing you want is your invoice showing a price, but when you look at all the invoices for that month, to show a different amount in the view. Same goes for reporting, make sure that when you have a calculated field, you use that in the report.

Enjoy!

This is just a quick observation. You might be tempted, for the sake a clarity, to create an additional field next to the Contact phone number to capture a phone extension.

image

Even though it might seem like a very good idea, after all a lot of companies do still use phone extensions for each employee, when users will synchronize with Outlook, this field will of course not be mapped to anything in Outlook. Obviously, it’s a custom field, so it makes sense.

Anyway, the only way to store an extension and have it mapped between CRM and Outlook is to mark it in the phone number field. Try to use a convention across the company, so you can handle that in a formatting script.

I am still surprised at how many people still mark extensions with the following format:

(999) 999-9999 x999

or

(999) 999-9999 ext999

One note, for the sake of telephony, if you use a comma [,] instead of the [x], the cell phones will know to interpret that as a pause, and, once dialed, should be able to dial the number, followed by a pause and then the extension.

Make it easy for the mobile users to dial phone numbers!

Enjoy!

You might be reading this topic, and think it’s just scripting, and just like any other form. What’s different?

Now, most fields we can script against without a problem. But let’s focus on the Extended Amount field. There is a system calculation that takes place, and if you try to enable the field for editing on the form, you will realize that you can’t.

Funny enough though, assigning a value to the field in JavaScript “almost” works.

var calculatedValue = … ; // put your formula here

Xrm.Page.getAttribute(“extendedamount”).setValue(parseFloat(calculatedValue));

Don’t be fooled by the fact that the field value indeed updates, because that’s only on the screen. Once you save the Quote Product, the value automatically gets re-calculated based on the built-in formula, and your result is off.

The way to override that value is by writing a plugin, but that’s besides the point of this post. I was looking at alternatives using JS. In some circumstances you just can’t get the result you want without writing a plugin, but for easy things, you could basically take the following approach:

  • Create a new Unit Price field on the form.
  • Hide the default Unit Price field.
  • Do your calculations based on the custom Unit price field, update the unit price (adding discounts and other adjustments you want to make), and populate the new value in the default Unit Price field (the one you have hidden).
  • Using this new price, you can take advantage of the system calculation, and make sure the Extended Price gets updated.

image

For a Write In product, this is not a problem, but for an Existing product, this will only work if Override Price is selected. Otherwise, the calculated value is based on the price as it’s defined in the price list associated product.

Enjoy!

Just a reminder to everyone, Mark’s book is out and available for ordering from Packt Publishing.

As I had the opportunity to proofread it, I have to say that the book is great, and Mark really pushed the limits on creating Dashboards in CRM 2011. It’s a great effort, and a very hot topic.

Great work!

Every now and then I get stuck on something where I didn’t pay enough attention when I was reading the documentation. This is one of those cases.

I was just playing with some OData scripts, and moving from one machine to another I realized that my calls were prompting for re-authentication on one of the machines.

Anyways, I go back to the documentation, which by the way is here, and one of the notes states:

“If you access the server locally using http://localhost or use an IP address rather than the actual name of the server, this will not be reflected in the value returned by this function. This means that if you are making web service calls or accessing web resources, Internet Explorer will apply security settings that apply to requests that cross domains. To avoid this, always connect to Microsoft Dynamics CRM using the standard URL.”

Interesting. There’s some work-around posts online, one of them being the use of document.location.

Just in case, if you ever find that users get prompted for authentication when running an OData call, that should probably be the first place to check.

Enjoy!

These are probably the most common generic data files I use for data load. I’ve posted them here for others to use as a starting point, but mostly for me to retrieve them easily rather than have to dig for them through my portable drive.

Canadian Provinces

USA States

Countries of the World

Enjoy!

July 26, 2012: Links have been updated to point to the new location of the files.

Working with lookup fields in CRM when using JavaScript is a little different due to the way the entity is handled. The following snippets will allow you to both read a value in a look-up, as well as to populate a value in the look-up (for cases when you need to pre-define a value).

Reading the selected value in a lookup:

var lookupItem = new Array();
lookupItem = Xrm.Page.getAttribute("new_specialty").getValue();

if(lookupItem[0] != null)
{
    var name = lookupItem[0].name;
    var guid = lookupItem[0].id;
    var entType = lookupItem[0].entityType;
}

Writing to a lookup:

if(new_Country == null)
{
    // alert("Preparing to set Country:");
    var countryName = "Canada";
   
    var lookupData = new Array();
    var lookupItem = new Object();
    lookupItem.id="{A53E3645-912A-E111-92BB-00155D146C19}";
    lookupItem.name=countryName;
    lookupItem.entityType="new_country";
   
    lookupData[0] = lookupItem;
    // alert("Assigning Country to Field:");
    Xrm.Page.getAttribute("new_relatedcountryid").setValue(lookupData);
}

Enjoy!

In some instances, you might need to put a lookup on a form, and based on the selection in that lookup, retrieve additional data about the entity referenced. One such example could be either the standard entities like Account or Contact, or a custom entity you have created.

The following snippet will help you do that, but first, be aware of a few things:

1. Using OData, you can make calls back to the server, and get the values you need. Whether calling your custom entity, or the default ootb ones, the easiest way to determine what you are calling is to have a look at the XML returned by a call to the web service:

http://[servername]/[orgname]/XRMService/2011/OrganizationData.svc

the return XML will give you all the available entity names. Find the one you need in there, as you will be using it in the script.

2. Use the following script on lookup change event:

        try
        {
            //Get entity data;
            var serverUrl = Xrm.Page.context.getServerUrl();

            var odataSelect = serverUrl + "/XRMServices/2011/OrganizationData.svc/new_specialtiesSet(guid’" + guid + "’)";
            // alert("ODATA Select: " + odataSelect.toString());
           
            $.ajax({
                type: "GET",
                contentType: "application/json; charset=utf-8",
                datatype: "json",
                url: odataSelect,
                beforeSend: function (XMLHttpRequest) { XMLHttpRequest.setRequestHeader("Accept", "application/json"); },
                success: function (data, textStatus, XmlHttpRequest) {
                    var org = data.d;
                    //Change form data
                    Xrm.Page.data.entity.attributes.get("new_specialtydescription").setValue(org.new_Description);
                },
                error: function (XmlHttpRequest, textStatus, errorThrown) {
                    alert(‘OData Select Failed: ‘ + odataSelect);
                }
            }
            );
           
        }
        catch(err)
        {
            // handle the error

        }

3. Observe two highlighted sections:

new_specialtiesSet is the value obtained from the XML returned by the web service call. To this value we pass the GUID of the current entity, which we can get by using this script:

var lookupItem = new Array();
lookupItem = Xrm.Page.getAttribute("new_specialty").getValue();

if(lookupItem[0] != null)
{
    var name = lookupItem[0].name;
    var guid = lookupItem[0].id;
    var entType = lookupItem[0].entityType;
}

org.new_Description is the actual field name in the looked-up entity (new_Description).

This way you can start populating current form fields with values from the look-up entity selected by the user. Be aware though that there might be a delay from look-up value change until the call takes place, results are returned and fields are populated. Depending on the environment, this could be visible or instant.

Enjoy!

Issue: no tracing logs or logs at the wrong/default location.

I was looking at some point for the tracing logs, and I could not find anything on the system. First off, the default location for tracing logs is at

C:\crmdrop\logs

but hey, that folder does not exist.

You can use PowerShell to enable tracing, as described in the following MSDN KB article:

How to enable tracing in Microsoft Dynamics CRM

basically, I’ll save you the read, it boils down to the following commands:

Add-PSSnapin Microsoft.Crm.PowerShell

Get-CrmSetting TraceSettings

This will give you the status. If the results shows Enabled:False go ahead and execute:

$setting = Get-CrmSetting TraceSettings

$setting.Enabled=”True”

Set-CrmSetting $setting

Get-CrmSetting TraceSettings

The result should show now Enabled:True

But now, why use the default directory? You might want to shoot the logs on a different drive. And also, make sure the path exists, as just enabling tracing will not actually create the path for you. Where is this path defined, anyway?

You have to fire up regedit (with the proper disclaimer that any changes you make here could potentially render your server unusable, and you might have to reinstall windows, etc…).

The setting is in:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM]

you will find there “TraceDirectory” defined with the default value. If you decide to change that, make sure that the path exists, and that the Workflow service account has permissions to this location.

Oh, and by the way, turn off tracing when not needed, as it has an impact on performance.

Enjoy!

MVP Reconnect

Check out my course [Video]

Dynamics 365 Customer Engagement Administration

Dynamics 365 Customer Engagement Administration

Check out my course [Video]

Configuring and Extending Dynamics 365 Customer Engagement

Configuring and Extending Dynamics 365 Customer Engagement

Check out my course [Video]

Getting Started with Dynamics 365 Customer Engagement

Reviewed Book

Implementing Microsoft Dynamics 365 for Finance and Operations

Implementing Microsoft Dynamics 365 for Finance and Operations

Reviewed Book

Microsoft Dynamics 365 Extensions Cookbook

Microsoft Dynamics 365 Extensions Cookbook

Check out my Book

Microsoft Dynamics CRM 2016 Customization - Second Edition

Microsoft Dynamics CRM 2016 Customization - Second Edition

Check out my Book

Microsoft Dynamics CRM Customization Essentials

Microsoft Dynamics CRM Customization Essentials

Check out my Book

Microsoft Dynamics CRM 2011 Scripting Cookbook

Microsoft Dynamics CRM 2011 Scripting Cookbook

Reviewed Book

Microsoft Dynamics CRM 2011: Dashboards Cookbook

Microsoft Dynamics CRM 2011: Dashboards Cookbook

Enter your email address to subscribe to this blog and receive notifications of new posts by email.

Join 608 other followers

Follow Dynamics 365 Wizardry on WordPress.com