Search This Blog

Friday, February 24, 2012

Contact Info / Label (CRM 2011)

Although the built-in Word Mail Merge can create nice personalized mailing labels, sometimes users don't want to go through all the steps Word requires to generate just one label. That is why we add a "Contact Info Summary" concatenation on most of our clients' Account and Contact forms, for a quick copy-paste option.

The code below applies to Contacts, but it can be easily adapted for the Account, Lead and Address forms.

1.    Start by creating a new memo attribute (“Multiple lines of text”) that will hold your concatenated label. In our example, we named it “new_contactinfosummary”. We recommend making it non-searchable to keep the fields list cleaner.

2.    Add the field to the form. Layout is up to you, obviously, but we recommend making it read-only, to ensure that users don’t start typing in there, thinking individual fields will update from there (true story…).


3.    Add the following 2 functions in a web resource.

function BuildContactInfoSummary() {
    //------- Load the function to build the Contact Info Summary
    var Label = "";

    if (Xrm.Page.getAttribute("salutation").getValue() != null)
    { Label = Xrm.Page.getAttribute("salutation").getValue() + " "; }

    if (Xrm.Page.getAttribute("firstname").getValue() != null)
    { Label = Label + Xrm.Page.getAttribute("firstname").getValue() + " "; }

    if (Xrm.Page.getAttribute("lastname").getValue() != null)
    { Label = Label + Xrm.Page.getAttribute("lastname").getValue(); }

    if (Xrm.Page.getAttribute("jobtitle").getValue() != null)
    { Label = Label + ", " + Xrm.Page.getAttribute("jobtitle").getValue(); }

    var OrgName = Xrm.Page.getAttribute("parentcustomerid").getValue();
    if (OrgName != null)
    { Label = Label + "\r\n" + OrgName[0].name; }

    if (Xrm.Page.getAttribute("address1_line1").getValue() != null)
    { Label = Label + "\r\n" + Xrm.Page.getAttribute("address1_line1").getValue(); }

    if (Xrm.Page.getAttribute("address1_line2").getValue() != null)
    { Label = Label + "\r\n" + Xrm.Page.getAttribute("address1_line2").getValue(); }

    //ENABLE THE FOLLOWING IF YOUR FORM INCLUDES STREET 3:
    //        if (Xrm.Page.getAttribute("address1_line3").getValue() != null)
    //        { Label = Label + "\r\n" + Xrm.Page.getAttribute("address1_line3").getValue(); }

    if (Xrm.Page.getAttribute("address1_city").getValue() != null)
    { Label = Label + "\r\n" + Xrm.Page.getAttribute("address1_city").getValue(); }

    if (Xrm.Page.getAttribute("address1_stateorprovince").getValue() != null)
    { Label = Label + ", " + Xrm.Page.getAttribute("address1_stateorprovince").getValue(); }

    if (Xrm.Page.getAttribute("address1_postalcode").getValue() != null)
    { Label = Label + "   " + Xrm.Page.getAttribute("address1_postalcode").getValue(); }

    if (Xrm.Page.getAttribute("address1_country").getValue() != null)
    { Label = Label + "    " + Xrm.Page.getAttribute("address1_country").getValue(); }

    if (Xrm.Page.getAttribute("telephone1").getValue() != null)
    { Label = Label + "\r\nBusiness Phone: " + Xrm.Page.getAttribute("telephone1").getValue(); }

    if (Xrm.Page.getAttribute("emailaddress1").getValue() != null)
    { Label = Label + "\r\n" + Xrm.Page.getAttribute("emailaddress1").getValue(); }

    Xrm.Page.getAttribute("new_contactinfosummary").setValue(Label);
    Xrm.Page.getAttribute("new_contactinfosummary").setSubmitMode("always");
}

function UpdateContactInfoSummary() {
    //------Update the Contact Info Summary on updatable records
    if (Xrm.Page.ui.getFormType() == 2) {

        //------Force a save if the Contact Info Summary was empty ** NOTE: remove this following statement if you DO NOT want to force a save -- i.e., if you have onSave code that you do not want triggered right away
        if (Xrm.Page.getAttribute("new_contactinfosummary").getValue() == null) {
            BuildContactInfoSummary();
            Xrm.Page.data.entity.save();
        }
        else {
            BuildContactInfoSummary();

            //------Disable the "do you want to save?" alert if the Contact Info Summary hasn't changed
            if (crmForm.all.new_contactinfosummary.IsDirty) crmForm.detachCloseAlert();
        }
    }
}

4.    Add UpdateContactInfoSummary as an onLoad event and BuildContactInfoSummary as an onSave event.

5.    Save and publish customizations.

Wednesday, February 22, 2012

Report Uploading Error

I was getting an error uploading custom reports on a customer's CRM 4.0 deployment.  When I would upload the report, I would get the following error:


Checking Google and CRM Forums it seems like there are a lot of people with this error.  A common mistake is creating a report in a new version of Visual Studio (2008) and targeting an older version of SQL (2005) reporting services.  This was not my problem, and I had been able to upload reports before.

Now, not exactly sure why, but I have had issues with reports on CRM before, and the process of playing around with encryption keys has resolved some issues.

On the SQL Report Server, I went to Start -> All Programs -> Microsoft SQL Server 2008 -> Configuration Tools -> Reporting Services Configuration Manager



I clicked connect and then clicked on encryption keys, and then backup. 

I entered a filename and path, passwords and that was it! 



I exited Reporting Services Configuration Manager and I could now upload custom CRM reports with ease.

I hope this helps someone in the future.  If anyone could give an explanation why this would fix it, I would appreciate it!

Cheers
Nick


Thursday, January 26, 2012

North American Formatting of Phone Numbers in CRM 2011

"Standardizing data entry" is often one of the top concerns our clients want their CRM solution to address. Creating a simili-input mask while still allowing users to enter additional notes when using an asterisk (*), here is code we use to help with the formatting of North American phone numbers.


Please note:
  • This code is for CRM 2011. If you're interested in our CRM 4.0 version, feel free to contact us and we'll gladly share it with you.
  • The function must be added to a web resource accessible to your form, and coupled with an onChange event on the phone number field itself. For example, the following would format the main phone field on the Account form >    function telephone1_onchange()
            {
                PhoneFormat("telephone1");
            }
  • We use the out-of-box address1_country field to determine if the phone number should or shouldn't be formatted. If you're using a custom field for the country, make sure to modify the code accordingly.

//------Format a 10-digit phone number to 'xxx xxx-xxxx', with the option to add stuff after the asteriskfunction PhoneFormat(oField) {
    var field = Xrm.Page.getAttribute(oField);
    if (field.getValue() != "undefined" && field.getValue() != null) {
        var country = Xrm.Page.getAttribute("address1_country").getValue();
        if (country == "Canada" || country == "United States" || country == "Bermuda" || country == "Mexico") {
            var sTmp = field.getValue().replace(/[^0-9,*]/g, "");
            if (sTmp.length == 10) {
                field.setValue(sTmp.substr(0, 3) + " " + sTmp.substr(3, 3) + "-" + sTmp.substr(6, 4));
                field.setSubmitMode("always");
            }
            else {
                if (sTmp.length > 10) {
                    if (field.getValue().search(/[*]/g) > -1) {
                        field.setValue(sTmp.substr(0, 3) + " " + sTmp.substr(3, 3) + "-" + sTmp.substr(6, 4) + " " + field.getValue().substring(field.getValue().search(/[*]/g)));
                    }
                    else {
                        field.setValue(sTmp.substr(0, 3) + " " + sTmp.substr(3, 3) + "-" + sTmp.substr(6, 4) + " ext. " + sTmp.substring(10));
                    }
                }
                else {
                    if (Xrm.Page.context.getUserLcid() == 1033) {
                        alert("This number should contain 10 digits. Please verify the data entered.");
                    }
                    if (Xrm.Page.context.getUserLcid() == 1036) {
                        alert("Ce numéro devrait contenir 10 chiffres. Veuillez vérifier et faire les ajustements nécessaires.");
                    }
                }
            }
        }
    }
}

Sunday, December 18, 2011

Catching up with the Cloud

By now most of you are sick and tired of hearing about “The Cloud”.  So bear with me for yet another “Cloud” blog posting, but looking at a Dynamics CRM topic that I have not yet seen covered.  Also bear with me in that I will be shamelessly plugging our own organization.
What I will be talking about is moving “on-premise” Dynamics CRM deployments to cloud Dynamics CRM deployments and keeping all data, reports, customizations, etc.
Now that Dynamics CRM 4.0 has been out for a few years, a lot of “on-premise” clients will of course be looking to upgrade to Dynamics CRM 2011 to take advantage of the new features and capabilities.  The upgrade process we found is fairly straight forward when following the proper steps and ensuring that all customizations and configurations either continue to work or are adjusted/converted to meet CRM 2011 requirements.  There are many other postings and tools to help with this process.
However, when looking at upgrading, there are a lot of other considerations and for some organizations actual roadblocks from moving from CRM 4.0 to CRM 2011.
While we are diligent in letting our customers know when their software enhancement is about to expire, there are instances where the software enhancement has lapsed.  For some of our direct customers, this is usually due to budgetary constraints.  We have also come across some customers who were never properly informed by their partners about software assurance or even that it had expired.  To get them on board with acquiring CRM 2011, the process involves either paying large penalties or even having to completely re-purchase CRM 2011 licenses.
The other limiting factor is hardware and software.  CRM 2011 requires 64 bit architecture as well as potential upgrades to Windows and SQL server.  Not to mention implementing ADFS if internet facing deployment is required.   
Considering hardware and software upgrades, enhancement catch-ups, for some customers this is a very daunting expense just for the sake of upgrading to CRM 2011.
At Ready BMS Ltd we now provide a service to bring these on-premise customers to the cloud.  Not only setting them up with a cloud version of Dynamics CRM, but also bringing all the data, reports, customizations over as well.   We currently host many of our CRM 4.0 and CRM 2011 customers at our secure Canadian-based hosting facility.  To bring a customer from an on-premise deployment to the cloud usually involves getting a copy of the database/customizations and redeploying/upgrading to a newly provisioned hosted version of CRM.  We do have the ability to test and allow some extensions that are not available with Dynamics CRM online.
By eliminating the software assurance, hardware and software requirements we are able to give these clients the full CRM 2011 experience at monthly per user fees as opposed to large capital expenses.  For some clients they would spend up to 10 years in hosting fees to get the equivalent in hardware, software and support to have the equivalent system on-premise.
Of course, if down the road the customer wants to move back on-premise, we can facilitate that as well.
If you or your customers are in a situation where you are running Dynamics CRM on-premise and want to upgrade, but are missing some key components and want to consider a cloud solution, please reach out to us and we will be happy to help you “catch up with the cloud”.  Please send an email to “crm <<at>> readybms.com”
Some features of our unique Dynamics CRM hosting services:
·         Ability to provide both CRM 2011 and CRM 4.0 hosted
·         Monthly fee of $50 per user per month, no user minimum, no time minimum.
·         Secure Canadian Data Center (not under jurisdiction of the United States Patriot Act.)
·         Ability to migrate CRM to and from on-premise and hosted.*
·         Ability to provide hosted Dynamics CRM Email Router.*
·         Ability to allow some extensions/customizations not possible on Dynamics CRM Online (will require testing and certification by our team)*
·         Other hosted Microsoft software such as Exchange and SharePoint available as well.*
*Additional professional service fees may apply.

For those of you in US, there is a promotion going on to get on Dynamics CRM online, which may be a viable option as well, altough it is not clear how you would get the CRM data/system moved over if at all:
http://community.dynamics.com/b/dynpartnercommunity/archive/2011/09/30/make-the-move-to-microsoft-dynamics-crm-online-campaign-and-offer.aspx

Coming soon, a blog posting about "Social CRM"... JUST KIDDING!
Cheers
Nick

Friday, December 2, 2011

Stay small or grow?

Wow, talk about a subject that has EVERY possible angle covered in hundreds of articles. And yet, it remains a neverending discussion: should we grow the business or stay small?

There doesn't seem to be a shortage of work in the CRM sphere -- not in our playground, anyway. We've got plenty of work to keep three full-time employees quite busy, without much investment in terms of marketing or sales efforts. We are fortunate to have loyal clients with which we've truly developed a good relationship, and that we continue to work with to help them get the best out of their CRM. Opportunities are coming to us -- directly and through select partners that we work with. We have to constantly remind ourselves of the importance of saying no, to maintain a manageable workload. The temptation to grow the business is strong... so why not?

Well, for one thing, we started the business because we like to do what we do, the way we do it. Sure, a couple of days a year, we have to do bookkeeping, pay bills, deal with office-related stuff. But the majority of the time, we focus on what we like to do and what we do best: delivering solutions, big or small, that help our clients. Would we be able to maintain that focus and share that vision as the company grew? Would we still be able to work in our business, or would we spend most of our time working on our business? Tidbit of wisdom from The E-Myth Revisited: understanding the technical work of a business doesn't mean understanding a business that does that technical work...

We like to do what we do, the way we do it. We're less driven by money than by non-pecuniary benefits (being one’s own boss, having flexibility of hours, etc.). As Nick says: "When you're your own boss, you get to decide which 20 hours of the day you want to work"... We like to think that we have the luxury of choosing who we work with, and who we work for. We work with like-minded collaborators (personally, I love the concept of the "managers of one") and find that we work best with clients whose corporate values are similar to ours. But what if the company grew and we had to say yes to work because we have to, in order to generate enough revenue to sustain the growth?

Here are a few quotes that I'll post next to my computer, for the next time this conversation comes up internally... again:
  • The beauty of entrepreneurship is that it gives you the opportunity to create a business that delivers what you want. (Forbes)
  • In order to be successful, a business doesn’t need to be big, it just needs to be big enough to achieve your goals.(Forbes)
  • Every business has a sweet spot for size, often smaller than they think. It is at this sweet spot where you have the right number of people, the right skill sets, and the right customers. (http://launchany.com/grow-big-stay-small/)
  • There should be no shame in declaring that you want to keep your business small.

Oh, and please don't hold any of the above against me if we meet in 5 years and Ready BMS has grown to a ridiculously larger size... "Il n'y a que les fous qui ne changent pas d'idée!"

Tuesday, November 22, 2011

LINQ to CRM Caching Issue

Recently I was given the task to create a fairly simple ASP.NET application to import records to a Microsoft Dynamics CRM 4.0 system from an Excel file. I was using LINQ to CRM and because some of the records being created were immediately required to link to other new records, I had to commit changes to the CRM database fairly frequently, and then immediately pull the newly created record.

Things were running along quite smoothly, when suddenly I started getting errors that the newly created record didn't exist. I could clearly see the record in CRM, so I knew it was being created, but could not figure out why it was suddenly not being found. It finally occurred to me that the original dataset was being cached, and was not being refreshed on subsequent requests.

After a little searching, I came upon a forum posting describing the same issue I was having, with a solution that worked like a charm for me. Hopefully it will help someone else out there.

I added the following method to my code, and right before I tried to retrieve the newly created record, I called it to clear the cache so that the dataset would be refreshed.

public static void ClearCache(string entityName)
{
    const string format = "adxdependency:crm:entity:{0}";
    var dependency =
        string.Format(format, entityName).ToLower();
    var cache = Microsoft.Xrm.Client.Caching.CacheManager.GetBaseCache();
    cache.Remove(dependency);
}
This solution worked perfectly for me, I hope it helps someone else out there.

Tuesday, November 15, 2011

Issue with Publishing Reports for External Use

We use Microsoft Dynamics CRM for almost everything; leads, opportunities, project planning, resource planning, time tracking and very importantly, invoicing.

Over the years we have developed a lot of code to easily enter our billable time and generate invoices.  One key Dynamics CRM add-on that we have is the "mPDF" software from Magnetism Software Solutions, you find more details here: http://www.magnetism.co.nz/solutionscasestudies/solutions/mpdf.aspx.

Basically it is a plug-in that lets you generate reports as PDFs and attach them to an email in a workflow.  For us, this allows us to fairly quickly fire off our invoices, project updates or schedules to our partners and clients.

In order for the mPDF software to work you need to publish the report for external use.

However, I had an issue where the report wasn't getting generated.  I checked the logs and saw that the MSCRMAsyncService was generating an error:

"System.Web.Services.Protocols.SoapException: One or more data source credentials required to run the report have not been specified."

This was not an issue with mPDF, but rather an issue with running reports that had been published for external use.

I navigated to the SRS Report Manager URL ("http://" followed by the reportserver name "/reports") and when I tried to run the external report I got prompted for credentials.  This should not happen. 

You will notice that any report that gets published for external use gets put in the root of the folder that represents your CRM organization.  The rest of the CRM reports remain in a folder called "custom".  The regular CRM reports will use a data source called "MSCRM_Datasource" in the custom folder, and the external reports will use the MSCRM_Datasource that is in the root of the CRM org folder (see example:)


SRS Report Manager

If look at the datasource in the custom folder for non-external reports, it should look something like this:
Internal CRM Reports Datasource
My problem was that the datasource for external reports for some reason (OK, it *might* have been me, but it might have been a system issue as well) was that is was identical to the internal datasource.

When running a report from CRM it will supply credentials to the report, and this datasource is setup to accept that and then communicate with SRS to render the report (via the SRS connector in case you ever wondered why you had to install it).  If we run it from outside of CRM, it does not have the credentials (which incidently are not standard windows credentials either, but rather unique CRM supplied ones) and the report cannot generate.

Finding a correct example of the MSCRM_Datasource and how it should be setup for externally published reports, I updated the datasource in the root of the CRM org folder to look like this:


Externally Published Reports MSCRM_Datasource

I basically had to the data source type, the connection string and the connect using.  This had to use a more traditional data connection approach with windows security and not from CRM.  The tests were successful and I was able to run external reports again.

Here is a table outlining the differences between the two datasources:


Internal CRM Reports MSCRM_DataSource
External use CRM Reports MSCRM_Datasource
SRS Report Manager Location
\<<CRMORG>>\custom
\<<CRMORG>>
DataSource Type
Microsoft Dynamics CRM SQL
Microsoft SQL Server
Connection String
MSCRM Data Connector Connection String
Workstation ID=<<crmserver>>.Microsoft.Crm.Setup.Server;Data Source=<<sql instance>>;Initial Catalog=<<CRMORG>>_MSCRM;Connection Timeout=60;Integrated Security=SSPI
Connect Using
Credentials supplied by the user running the report
Windows Integrated Security


(replace anything in the << >> with your own settings)

I hope this post gave some insight on how the MSCRM_Datasource works for publishing reports for external use and perhaps will help you in future troubleshooting efforts!

Disclaimer: Before attempting to modify any of these settings, make sure you have backups, certifications, signoffs and confidence working on server side technologies. I supply this blog as information and take no responsibility for any inaccuracies or issues that arise.