Thursday, August 28, 2014

Saving a CRM form with missing required fields

I ran across an interesting problem in that I needed to allow a CRM user to save the progress of a form that has required fields.  The required fields are not truly required until the user initiates a separate submission step.  I was able to "temporarily" remove the required from the fields and then put it back on after the save using this script:


function onSave() {
    var i = 0;
    Xrm.Page.ui.controls.forEach(function (control, index) {
        if (typeof control.getAttribute == 'function' && typeof control.getAttribute().getRequiredLevel == 'function' && control.getAttribute().getRequiredLevel() == "required") {
            reqControls[i] = control;
            control.getAttribute().setRequiredLevel("none");
            i++;
        }
    });
    Xrm.Page.data.save().then(onSaveComplete, onSaveFailed);
    
}

function onSaveComplete() {
    reqControls.forEach(function (control) {
        control.getAttribute().setRequiredLevel("required");
    });  
}

Tuesday, February 25, 2014

The lock value must exist error when resetting ADX auto-number

If you try to manually reset the "Last Number Used" field in ADXStudio's Productivity Pack, you will receive an error that says, "The lock value must exist."  This is actually a good thing, because it means the locking code is working properly.  Here are the steps for resetting the Last Number Used field:


  1. Enter "1" in Lock Value field and Save
  2. Enter "1" in Lock Verification field.  Now you can change Last Number Issued to any value you'd like (e.g. "1000") and Save
  3. Clear the Lock Value field (blank) and enter "1" in Lock Verification field and Save
You are all done!

Tuesday, December 17, 2013

Dynamics CRM 2013 Spreadsheet Import Tricks

This is part 2 demonstrating how to upload a spreadsheet of bounced emails addresses to modify contacts.  In part 1, we created an Email Bounce entity and a Real-Time Workflow.
The first step is to download the Import template.  This step is optional and depending on the scenario. may make it easier (or more difficult).  In this case, it’s going to make creating the map easier, so let’s get started.  Navigate to your entity and click the Import Data – Download Template for Import and save the XML file. 
Most of the time your computer will not realize this is an Excel file, so to open the XML file, start Excel and use File – Open.  Now you can paste your list of email address into BOTH columns.  Save your changes to a new file (so you can reuse the template next week) and exit Excel.
Start the Import dialog and select your XML file in the first screen.  CRM will recognize that you want to upload Email Bounce records, but we need to edit the mapping, so click Edit.
We need CRM to lookup our Contacts using the email address, but it doesn’t do that be default, so we have to add it to the Lookup reference.  Click on the little icon next to the Contact field and select the Email field from the list of Contact fields.
Click Next until you get to the Finish screen.  Tip: give this Mapping a name, so you can reuse it next time.  Click on the “Imports” link to watch the process unfold. 
If you have any errors then you can export the failed rows and manually process them.
Remember that Mapping we saved, well reusing it is not as easy as you’d think…when uploading XML files, there’s a strange trick to it.  You still have to click the Edit button after uploading the XML file, but when you get to the Map Record Types dialog, click Back and you are magically transported to the Select Data Map dialog. 


After that, you just click Next, Next, Next…as quick as you can and you’re finished.

Dynamics CRM 2013 – Handle Bounced Emails


If you have a lists of email addresses that returned as bounced, how can you update your Dynamics CRM contacts?  Easy!  Create a new entity and put the power of Dynamics Workflows to use.
The first thing we’re going to need is a new Entity – let’s call it “Email Bounce”.  Let’s keep this entity super-simple and turn off all of the Communication and Collaboration options.


Before we hit Save, let’s change the Primary Field so we can use it to store a text version of the email address.  Rename it to Email and set the length to 200.

After you save your entity, open the Form and add a new Lookup field for Contact.  Save and Publish your entity.  Now on to the workflow.
Create a new Process - either in your Solution, or in the Processes subarea of the Settings menu.
Now you have a decision to make…well, that is if you are using CRM 2013.  I chose to create a Real-Time Workflow because I am planning to Deactivate my Email Bounce records once a matching Contact is found.  I will be uploading these emails using a spreadsheet, and I know there will be times when my email address does not find an exact match.  If two contacts are found, or none, I’d like the Email Bounce record to “hang around” so we can manually investigate.  With a Real-Time Workflow, when the Contact Lookup is populated, the screen will refresh and my Email Bounce will be Inactive, signaling success.  If I used a regular workflow, the record would be inactive, but the user wouldn’t see it unless they manually refresh their view.  Score one for CRM 2013!  Here’s how I setup my workflow.  Note, mine runs on Create and Update (of the Contact field)

Now, if you’ve never used CRM’s Import features, you are in for a real treat!  Check out Part 2 –Data Import Tricks.

Monday, November 11, 2013

Microsoft Dynamics CRM 2013 - New Workflow Features

Synchronous Workflows

There are a bunch of great new features in CRM 2013.  One particularly powerful one is synchronous workflows.  It used to be that workflows could only run asynchronously, which made them an inappropriate choice for many automation scenarios.  For example, if you needed to calculate a value that would be displayed to the user, workflows were a bad choice since they might take two seconds or 20 seconds, but either way, you were not going to see the results until the user refreshed the page sometime after the workflow completed.

If we turn our attention to another new feature in 2013, the Process Flow, we notice that the Lookups do not allow us to set any “filtering” like we can on the form.  For example, it’s typical to setup a filter between an Account field and a Contact field.  That way, you only have to search through a list of Contacts related to the selected Account.

Let’s create a handy Contact Abbreviation field to demonstrate synchronous workflows and make it easier to find a particular contact in the Opportunity Process field.
Sync1

We’ll be using the Manipulation Library written by Carlton Colter and available for download on CodePlex.  This will add a number of useful String and calculation steps to your workflow Add Step menu:
Snyc2
Add a field to the Contact to hold the Abbreviation (optionally add it to the Form)
Sync3
Now let’s use the Manipulation Library’s Substring step to calculate the Account abbreviation.  Follow these Steps:
  1. Before we get into the fun stuff, let’s make sure our Workflow does get confused.  Add a “short-circuit” to only run if we actually have an Account to work with (remember, Company Name is of type Customer which could also be a Contact!):
    Sync4
    Interesting discovery – if you stop the workflow with status of Cancelled it will throw and error back to the user. 
  2. Now Click Add Step and find the “Strings Utilities” – you may need to scroll (note difference in spelling seems to be a bug in the library) and select Substring
    Sync5 
  3. Give the step a good “variable sounding name” since we’ll be using this later in a formula.  I called mine Account Abbreviation.
  4. Click Set Properties and then click in the Text value box.  Then select Related Entities – Company Name (Account) in the right menu.  Select Account Name and click Add.  Lastly click OK. Sync6
Repeat this process for First Name and Last Name but change the Length to 1
Now that we have all of our abbreviations, we just need to update the Contact, so click Add Step and Update Record.  Give the step a name (e.g. “Update Zip Finder”) and click Set Properties
Now we need to add the result of the three substring steps above into our Contact’s field.  Unless you added the new field to the Contact form, you will need to scroll down and find it among the field “Additional Fields” section:

Sync7
Now for the fiddly part.  Select the Zip Finder field and then in the Look For, select Account Abbreviaion – Result and click the Add/OK like above.  To add the other characters you will need to click in the Zip Finder field again, AFTER the highlighted slug and remove the extra whitespace.  Now repeat the step for First and Last name.  Your formula should look like this:
Sync8
Now just click Activate and again in the confirmation dialog:
Sync9


Let’s give this a try.  Update a few contacts so you have some Zip Finders to test with.  I added a contact named Johnathan Smith to Blue Yonder Airline.  Hey, when I search for “blu” I don’t see anything!  That’s because we need to add our new field to the entity’s Quick Find View.  The super-fast way to edit the system views is to return to the Contacts list and click the ellipses in the ribbon (…) and System Views:
 Sync10
Just click the Add Find Columns in the right menu and select your new column.  Make sure you click Publish on the Contact entity (or Publish All Customizations) to make the change effective.
Sync11

Now when you type “Blu” you get a list of all contacts that have a “Blu” anywhere in their name, company, email, etc.
Sync12
In many systems that will return too many records to find the one we want.  But, if I type “blujs” (or even “bluj”) I’m searching for a very distinctive string and will work in other locations like Lookups!
Sync13
Now this abbreviation scheme may not work in every situation, but the algorithm is very tweak-able for your particular application.

Synchronous Workflows vs. Plugins

There will definitely be debate about when to use a synchronous workflow over a plugin so here are some guidelines about when to choose real-time workflows:
  • Logic is relatively simple (if-then-else)
  • The business rules may change frequently
  • The data needed is contained in the primary entity or entities with N:1 relationships
  • The process needs to create or send a template-based email

Thursday, October 10, 2013

Inspired by greatness

Greatness comes in many forms, but it is not hard to recognize when you encounter it.  I am grateful to providential timing that I was able to get in under the wire of this one:
http://www.stevewiens.com/2013/09/20/rim-to-rim-what-i-learned-in-the-womb/

Thursday, September 19, 2013

Fix Virtual Box No Internet problem with Domain Controller

I struggled for days trying to get my Windows Server 2012 VM running on Virtual Box to connect to the internet.  In the end, it turned out to be a DNS issue because I was running a DNS server on my Domain Controller.  Here's how I fixed it:

Open Command Prompt and type: ping www.google.com


What you will probably see is “could not resolve host”.  If you do, then confirm that your DNS is pointing to the wrong place by typing: ipconfig /all



Down at the bottom you will see the DNS Server(s) you are using.  If it is set to 127.0.0.1 then you need to find a “real” DNS server.

On the HOST operating system open a command prompt and type: ipconfig /all and note the DNS server.

Back on the guest VM, open up the TCP/IP properties by going to Network Sharing Center and clicking the connection.  On the Ethernet Status dialog click Properties.  On the Ethernet Properties dialog click Internet Protocol Version 4 (TCP/IPv4) and click Properties:

On the TCP/IP Properties dialog, enter the address of your HOST’s DNS server and click OK

Go back to your command prompt and you should now be able to ping www.google.com