tisdag 25 augusti 2015

Mapping from opportunity through quote to salesorder

I've run into this issue a couple of times now so I thought it might be a good thing to collect what I've found about this issue. If you noticed that the order of the lines from an opportunity isn't copied from opportunity to quote and then on to salesorder. 

This probly ranks among the sort-of-supported, but it's not any SQL hacks involved so I think it's sort of kosher. 
All info is taken from https://community.dynamics.com/crm/f/117/t/140108 which in turn points to a bllog. This is a  summary of that.

First, run the following SQL command on your organisation db:
SELECT  EntityMapId
FROM    EntityMapBase
WHERE   TargetEntityName='quotedetail' AND SourceEntityName='opportunityproduct'
That will give you a guid to a mapping page which is interesting. When you want to do the same thing on quote to order mapping, change the target to "salesorderdetail" and the source to "quotedetail"

Now we use the guid provided by the nice database in the following URL: http://[x]/Tools/SystemCustomization/Relationships/Mappings/mappingList.aspx?mappingId=[y]. Change [x] to serverurl and organisation (myserver/testorg/) and the [y] to the guid just found in the database

This opens a mapping page where you can insert mapping from sequencenumber to sequencenumber and the products will be in the same order in both records.
I'm pretty much posting this to make it easier for me to find, maybe it's good for someone else too. Again, I haven't found out how you did this, just to make sure.

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se  
 

fredag 14 augusti 2015

Exchange rates per record, or any color you like

Since I started working with Dynamics CRM the "issue" of one exchange rate per currency has come up a couple of times. How do you handle it, when do you update, what do you do if you want to... 
A customer of ours wanted to have an exchange rate per record so how can you fix that and still be able to use the rest of the functionality.

This is by no means THE solution but it is one. I was fiddling around a bit with CRM when I got the problem. Could I write directly to the base currency, was there any other way around the issue, should we use some other field?

I started looking on the web for solutions and I found this short blog http://www.crmsoftwareblog.com/2012/11/dynamics-crm-2011-multiple-exchange-rates-for-currencies/ which pointed be in the direction of the RetrieveExchangeRate message. Having no idea, I had a look in the plugin registration and yes, there was indeed still such a message



















(Yes, I'm still using the 2011 plugin registration tool, it works and you can store multiple connections...)

So, having found this message and having no idea how to use it, I didn't find anything about it in the SDK either, so I started out with a pretty empty plugin which was called by the message which I step debugged in VS to see what was going on.

It would prove to be fired before everything else and the calling object was present as context.ParentContext. After that quick test I started getting stuff together. So, this is what I did:

IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));
            Entity parentTarget = ((Entity)context.ParentContext.InputParameters["Target"]);
            IPluginExecutionContext parentContext = context.ParentContext;


The usual suspects, set stuff up.

if (parentTarget.LogicalName == "crmk_testentity")
            {


Run the code only when we are interested of the result. Now you can do pretty much what you want, in my case we had the exchange rate in a parent object so I had to fetch that, it could also be the case that the currency was the base currency and the plugin didn't need to do anything. This meant I needed to fetch the currency and the wanted exchange rate. 

The magic happens with the output from the RetrieveExchangeRate plugin,  
context.OutputParameters["ExchangeRate"] = exch; 

"exch" is a decimal and you can set it to whatever you want and then CRM behaves as if it just retrieved the exchange rate from the system. Since we're using a plugin message and not doing anything realy naughty, more than pretty much a man in the middle attack on the system itself, this should be supported.

Happy coding

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se  
 

onsdag 8 juli 2015

Company Name not available in lead views

I was editing system views for a customer today and had some issues with the company name field on the lead system views.

It seems that this is a bug which has been reported to Microsoft connect, so please upvote this. https://connect.microsoft.com/dynamicssuggestions/feedbackdetail/view/955886/cannot-add-company-name-column-in-existing-standard-view-in-lead-entity

I found this in CRM 2013 but it seems that it's an issue in CRM 2015 as well. Here's a thread where I found the connect issue; https://community.dynamics.com/crm/f/117/p/122564/405479#405479

Please vote on connect so we get rid of these mighty annoying bugs.

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

tisdag 7 juli 2015

Part two of the time zone tombola

So, I did actually keep the "6 months timeframe" that I promised in the last part, just over two months is a bit longer than I planned this though. So how did I go on with our time zone issue?

The main idea is that we use the CRM time fields to keep track of stuff in UTC time. Those fields will always show the user when the meeting takes place in the time zone you have set in CRM.














As you can see in the picture I have set up two time blocks, "local meeting time" and "my time". The local meeting time is the time when the meeting takes place at the actual site. If we woul
d have a meeting in London, and this is my CRM running CET there would be a difference of one hour between the two where "my time" would be one hour ahead.

As you can see I also locked the datetime fields in my time so all editing happens in "local time".

Now on to JS madness.

Onload of the appointment form I fetch the starttime and endtime of the appointmen, if those aren't set I set them as new Date(), which I then make sure is on the hour of half hour. I also fetch the duration field, which is a tricky bastard I might add, and the custom timezone field.

The endtime is set as starttime plus duration if there are no values for start and endtime on the form.

Now things got a bit trickier, and here's why I don't like time zones. I use the same way that CRM uses the timezones for the script part so I set up a timezone setting array which looks something like this:
localSettings = [0, 10, 5, 0, 2, 3, 5, 0, 1, -60];

So, this is slightly greek but this is a settings array for UTC. The first element is timezone bias, which is 0 for UTC. To make it slightly worse it's negative for CET so you take the time i CET and add the bias to end up in UTC.
The second element is standard month, which is the month in which standard time is starting, no worries, well I might mention that January is 0 in JS. 
The third element is standard day, which could be a date but it isn't  since you change back to standard time on the fourth saturday after the fifth moon after midsommer, ish. That is which number of day this is, in this case the fifth time the day appears in a month.
The fourth element is standard day of week, which means which day we are lookin at, and since 0 is the first day of the week, it's a sunday.
The fifth element, standard hour, is what time of day you return the clock one hour. Which in this case means that in UTC you return the clock one hour at two in the morning.
 The following four elements are the same for DST and the final element is daylight bias, which again is negative.
I also fetch the users timezone settings from CRM to calculate UTC time.

With this info I calculate when DST starts and ends using the following code:
 var GetDst = function (inyear, month, day, dayofweek, hour,tzBias) {

    if (tzBias == 0)
        return new Date(2011, 1, 1, 12, 0, 0, 0);

    var returnDate = new Date(inyear, (month - 1), 1, hour);
    var testDate = new Date(inyear, (month - 1), 1, hour);
    var firstDayOfMonth = new Date(inyear, (month - 1), 1);
    var firstDay = firstDayOfMonth.getDay();

    if (firstDay != dayofweek) {
        if (dayofweek == 0)
            testDate.setDate(testDate.getDate() + (7 - firstDay));
        else
            testDate.setDate(testDate.getDate() + (dayofweek - firstDay));
    }

    testDate.setDate(testDate.getDate() + ((day-1) * 7));
    if(testDate.getMonth() != (month - 1))
    {
        testDate.setDate(testDate.getDate() - 7);
    }
    return testDate;
}


Here the inputs are the year from the appointment, in the first case I want DST start time for the year the appointment is happening, month, day, dayofweek and tzbias are from the settings array

First I set a date of the year, DST start month, the first day of that month and the hour that stuff happens. I alse set up en exact copy of that date. 
I the proceed with finding out which day of the week the first day of the month is and compare that to the daylight saving start day and if the don't match I find when the first "change day" of the month happens (say first sunday).
After this I apply the number of weeks that should be added and check if we're still in the same month, if not, remove one week. SIMPLE

The time presented in "My time" is set up by UTC time plus timezone difference and DST difference so to get UTC time from the form I convert that time with the info about 
I then check if the time we get out of CRM is within DST and apply the changes to get to UTC time. 

This is done since I can never be sure that the computer's timezone setting is the same as CRM settings so I need to calculate the time in the form based on the CRM settings, yes that made me feel a bit sick too.

After I've calculated what the "my time" times are in UTC time I can then apply the timezone info on that data and I know when the meeting is taking place at the local office.

What I also do is set the submitmode to never if it's anything else than a create form. You will also need onchange scripts that sets the submitmodes to relevant values when you change an appointment.

The duration field isn't really propagated in a way you would think when you change it so that has to be made dirty with code to be sent, very annoying and a source of errors I might add.

I hope this makes some sence. It's a bit tricky and I had to work quite hard to get it right. What started out as a "Oh, we just take whatever time CRM is giving us and add an hour and we're home free" ended up in a couple of hundred lines of scripts and a little less plugin code to handle the saves.

So as my commanding officers said after an order or information speech. Any questions, too late, dismissed!

Seriously, if you would stumble upon this and have similar issues, give me a holler and I'll try to help. I'm thinking of talking about the backend code sometime later, maybe in another two months :)

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

onsdag 24 juni 2015

Email Configuration button missing

No biggie, and quite documented but I'd like to point this out anyway. 

If you're not having any email configuration button in the settings area, then you have probably upgraded from CRM 2011 and the button isn't part of the sitemap. The solution is to add the following to you sitemap right aftert the <SubArea ID="nav_audit"...> tag,

<SubArea Id="nav_social" ResourceId="Social_SubArea_Title" DescriptionResourceId="Social_SubArea_Description" Icon="/_imgs/area/16_social.png" Url="/tools/social/social_area.aspx" AvailableOffline="false" />

It's pretty logic that you should add the social nav to get email configuration. Read more at
http://blogs.msdn.com/b/emeadcrmsupport/archive/2014/03/07/dynamics-crm-2013-email-configuration-tab-is-missing-from-the-settings.aspx

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

söndag 7 juni 2015

IFD/ADFS setup stumbles when you think you're done

I've been fiddling with IFD and ADFS a bit more than what's healthy the past couple of years and I still face the "What the h*** is wrong now"-moments from time to time. Admittedly they're a bit more rare and not quite as severe as they uses to be, thank god.

One thing I've been running into quite frequently the latest times I've been messing with IFD is that when you think you're done and you try to log on for the first time you get a "I can't connect to the ADFS-server"-message in the browser.
On the ADFS server the logs say "the element 'serviceIdentityToken' was fount to have invalid data", on the CRM server you have a "Exception information:
    Exception type: EncryptedTokenDecryptionFailedException
    Exception message: ID4036: The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier " and the CRM trace tell you something like "Microsoft.IdentityModel.Tokens.EncryptedTokenDecryptionFailedException: Microsoft Dynamics CRM has experienced an error" (and by the way, yes, that's the coherent part of that error).

You think, probably at least since I have, What happened, I just connected to all these servers.
So, what needs to be done? I can't tell you exactly what makes things work but if you update the metadata in the ADFS server manager, restart ADFS-service, restart the IIS you should be fine.

If that doesn't work, start browsing Chris Cognettas blog.

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

söndag 31 maj 2015

Which version of ADFS are you running?

When you are setting up an Internet Facing CRM you need to use an STS service which often means ADFS. So which version are you running?

 Now, CRM of different verisons supports different versions of ADFS and the complete list is in your implementation guide. But how do you check for which version you are running. It turns out you don't. But have no fear, Jorge is your man here. This blog https://jorgequestforknowledge.wordpress.com/2014/02/23/gathering-architectural-details-from-your-adfs-infrastructure-adfs-version/#comment-17198 helped me to determine which verison that was installed on a system. Really, you have to look at how the GUI looks and see if there are files available.

This feels so 2015.

Have fun and thanks Jorge!

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

torsdag 28 maj 2015

SQL Server instance name must be the same as computer name

I was installing a CRM 2011 server the other day to do an upgrade for a customer and, yes I know this sounds impossible but I ended up with an error I haven't seen before.

It really was my own fault but still. I had installed the SQL server on the machine and then renamed it which made the SQL server behave in a bit interesting way. My CRM installation whined a bit about the server name not being the same as the SQL instance name which made no sence at all to me but when the reporting services complained too I ran the reporting services setup tool and this showed me that it was looking for an SQL server with a different name than what I expected.

This blog article shows how to deal with it https://zhongchenzhou.wordpress.com/2012/04/29/dynamics-crm-2011-installation-error-the-instance-name-must-be-the-same-as-computer-name/ .You will have to re-point the reporting services too, but that's a bit more intuitive.

Someone else would probably say something along the lines of "my eight year old can do this".

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

onsdag 27 maj 2015

CRM 2015 Online spring update and Outlook client

The CRM Online 2015 spring update... Experience, or something (version 7.1) is out.

I was looking for the updates for the Outlook client and had some problems finding it so I thought I would post the link here. https://www.microsoft.com/en-us/download/details.aspx?id=46908

Thats it, happy CRMing

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

tisdag 28 april 2015

Import Data privileges and appointment errors

Data import is indeed a powerful tool that will allow you to update many records at once, however to my great surprise the security settings to allow a user to import data is not completely simple to understand.
Next, when you get a log full of error messages you suspect something's wrong...


The first problem I was facing this time is to import data that has been exported from CRM. This seems to be a pretty straight forward operation, and it should be, however the security settings makes it pretty much everything but simple.

The user that was going to do the import had pretty high level of rights to do things in the system but when she imported data that had been edited in excel after export the data import job was suspended in limbo saying "imported" (or something similar) with the job halting with an error saying "Failed to get priv user group information. k = <guid> privUserGroupId: <guid>, localSystemAdGuid: <guid>, Exception: System.Runtime.InteropServices.COMException (0x800706BA): The RPC server is unavailable. (Exception from HRESULT: 0x800706BA)"

This made me look at the AD and the PrivUserGroup,even though I suspected that it wasn't the actual problem, no luck there. As I suspected that this wasn't the problem I tried to import the file using a sysadmin account which actually worked.
As I was done troubleshooting I tried to find the correct security settings to import files and found them on the Microsoft forums. The winning lineup is the following:

* Data Import (all)
* Data Map (all)
* Import Source File (all)
* Web Wizard (all)
* Web Wizard Access Privilege (all)
* Wizard Page (all)

You can probably get away with BU rights to be able to import stuff to your own BU. The entire thread can be found at Microsoft forum. It's a good thing that these things are simple to solve, and that the error message isn't something like "User X is missing security right Y", that wouldn't make it as interesting.

Moving right along with the next issue which I also was facing at the same customer. They had a LOT of error messages in the trace logs saying  "
>Crm Exception: Message: recurringappointmentmaster With Id = 00000000-0000-0000-0000-000000000000 Does Not Exist, ErrorCode: -2147220969". This made me slightly nervous considering that the customer also have had some issues with performance that we are investigating at the moment. Now, to make things clear, we are NOT being nice to the appointment entity with some heavy, but supported, customizations so I wasn't exactly chocked to see errors being thrown here.

I want to say that there doesn't seem to be a problem with the appointment entity since it's ok to create appointments most of the time, but we've also seen an alarming amount of "hey something's wrong, you want to send data to Microsoft?" boxes so it might have been something that wasn't optimal. Today I was helping one of the users with monitoring what the system was up to when she was doing her work so I had some time to sit down and have a look at the logs, which is one of the best things I know.
This error message was pertty common as usual and I started looking for others that had this issue but nothing obvious came up so I thought what happens in a completely vamilla system, something I haven't trie yet.
I had a CRM that I hadn't modified anything, CRM 2013 SP1UR1 on premise that I popped up an appointment form in and entered "test" in the topic field, lefter everything else as is (some dates but that's it) and saved. This gave me the exact same error in the trace logs.

This ticked me off a bit. Microsoft actually ships a system, in it's fourth or fifth iteration of that version and it truly SPEWS out error messages in the trace log when you create an appointment. That is not OK.

If you get a lot of errors with recurringappointmentmaster with ID = empty guid, that's how CRM is supposed to work. Sorry to say this though.



Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

onsdag 22 april 2015

This is a draft post that I never finished, still the information is quite useful so I hope it helps someone. Read it as "a couple of months ago" :) //Rickard
 
It's been a while since I published something here, seems as the days are too short. Today I will discuss two problems I've encountered in the past weeks which gave me some (more) gray hair.

First thing happened this morning when a customer called saying that she couldn't run a report on an advanced find she had been using earlier. I tried to use the report on a small number of objects, 10 or so, on ALL objects and using the advanced find to select many objects (roughly 1700). I had no problems but when the customer did the same thing she got the following results: On a few objects the report worked as intended, on 250 objects it worked, on all objects it worked but when chosing all objects on all pages of the selected view after using the advanced find the report viewer just showed "error on page" at the bottom of the window. When closing the window I got prompted if I wanted to send info to Microsoft which I viewed and it said that "the object doesn't support the property or method".

Considering that I could use the report I set the system administrator role for the customer and when she tried again the report worked. A security issue one would think, well I removed the system administrator role to start test different possible scenarios but gave it a go again and tested the report. To my surprise it worked, the only thing I did was to assign the sysadmin role to the user, run the report and then remove it again. Very strange.

The other problem I had a few weeks ago when I was modifying existing, and working, code with a new function. Things went south pretty fast and I had to acquaint myself with the wonderful world of error messages in CRM 2011. What I did was that I needed to move variables from the pre operation state to the post operation state of a plugin. With these variables I would do an update and it had to be done after the operation.

Right, I consulted the all knowing SDK, The Junior Woodchuck Guidebook of Dynamics CRM. The answer was actually quite simple, SharedVariables. So since I wanted to pass a few variables I had a look at the structure which was a key-value pair so I figured I could pass an XML-object, which I did.

That was not the correct thing to do. There were no error messages when I did it but boy did things blow up when I used the plugin. It seems that you can't put anything serializable in the shared variables so I had to somehow enumerate the data that I put into the shared variables and then go through the set in the post state code, which worked quite alright actually. Lessen learned, don't put serializable objects in the shared variables, even if an XML might seem like something else.
In hindsight, I wonder if it might have worked with an XML as a string field which you read into an XML in the post state code.

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se

Time zones in Dynamics CRM, well all of them

Ok, so you're booking meetings in Dynamics CRM and it's mostly fine and dandy. The meeting starts at one o'clock so you book it at one o'clock. But what happens when you know you have a meeting at one o'clock in Helsinki, or in Auckland?

This is where things get a bit interesting. What you can do is to go to you personal settings, change it to Auckland (GMT + 12), which you can see in the picture below.





















Now, click ok, and you can book you meeting at 1 PM, invite all people that are supposed to attent and save it. Then return to your own time zone, in my case GMT+1 for Stockholm and the meeting time jumps to 3 AM as seen in below picture.















Ok, so far, so good. But if you're in an international organization and you book a bucketload of meetings every day, doens't this mean there will be a LOT of clicking?
The short answer is, yes, there will be a lot of clicking. How much you might wonder.

I have actually done the math. Now, considering that you change the time zone of your personal settings for each meating you book you need 5 clicks to get to the desired time zone, then wait for the form to reload and you can enter the start time of the meeting, and then save. If you want to return to your own time zone after saving, it's another five clicks, since you might want to check when the heck the meeting will take place in some civilized time zone, even thought the start time will most likely be far from civilized.
Now wait, if you're booking a lot of meetings, you might have several meetings in the same time zone you might think, and you don't have to check your own time zone each time you book a meeting.

Fair enough, let's say you book 16 meetings a day in at least 4 different time zones, that will give you at least 25 bonus clicks which might not seem much but you also have 5 reloads of the form that make the application perhaps not seem like the most smooth tool in the box. The customer will most likely point out that you can have different time zones for start and end time if you make the booking in outlook, so why on earth isn't it possible to book a meeting in a different time zone in CRM?

One can only speculate on the reasons, it is for sure that the reason  isn't that the application is from USA since USA alone has a couple of time zones. I seriously have no good answer to this.

The reason why I'm writing about this is of course since I have run into this with one of our customers. So how can you solve this?

There must be a couple of solutions to this and I will show you our solution but first a bit of background.

- One, there is a timezone format of the whole number field. It's broken, don't use it. I tried to use it and as soon as I inserted data in the field I got an error. I started a thread on connect for this issue, so please vote on Connect if you have an account so that might get fixed.
- Two, event with that field functioning, it's no walk in the park to make the time zones work...
- Three, all datetimes are stored in the database in Zulu time, which is UTC, ie, no daylight saving whatsoever, which I will come back to later. This means that you will have to do something with that time if you're working with the start/stop time programatically.
-Four, did I mention daylight savings? Yes, that will make it trickier.
-Five, and this is someting I didn't think about but I discover it rather harshly, you computer and your CRM might very well be running on different time zones.
-Six, did anyone say daylight saving?

Solution idea:
Keep the start and end time fields, you will need those, and add extra fields for start and end time which will show the start and end time of the meeting where the meeting takes place.

Right, this can be done, but how do we know in which time zone the meeting takes place?

Add a time zone field.

Ok, so how do we keep these fields updated? Let's write som js to keep them updated, take the time from CRM, add or subtract the relevant time difference and everything's fine. Well not quite.

I will continue on the solution next time, which I promise won't be another six months.



 

Rickard Norström
Developer at CRM-Konsulterna
www.crmkonsulterna.se