A topic which caused a lot of issues in my company for a long time were related to the Exchange Rate on the Opportunities, and more especially the Closed Opportunities since a "long" time when we had to update anything.
How the Exchange Rate is used on opportunities ?
You know that as soon as you close an opportunity (we assume that it's the last update the opportunity will have) it's retrieving the current value of the Exchange Rate in your currency entity and store it.
So if you decide for any reasons to do an update or re-open the opportunity closed 2 years ago you will be in trouble regarding your "_base" fields.
Because as soon as you will do any action to the opportunity, it will automatically retrieve the Exchange Rate of the day.
Let's assume that my default currency is € and i have an opportunity in $. When i closed the opportunity the Exchange Rate was : 1€ = 10$.
Now, i updated the Exchange Rate to 1€ = 5$ and when i re-open the record or update it, the Exchange Rate is correctly updated :
So you revenue_base changed from 1000€ to 2000€ and your only possibility to put back the old revenue_base is to change the Exchange Rate in your currency entity, update the record or close it, and put the current Exchange Rate back.
A lot of work for a number !
But we now figured out how to solve this issue automatically.
When we had to migrate our CRM 2013 On Premise to CRM 2016 Online we had the problem. So I searched around the web.
I ended up on something interesting, there is actually a Plugin message "RetrieveExchangeRate", so i digged into this direction.
Steps done to solved this :
- Create a field to hold the "historical" Exchange Rate (a simple decimal field make the job)
- Create a plugin on the entity Opportunity with the message Update/Create or whatever message you want and we will use the SharedVariables between plugins.
- Create a plugin on the entity : Transactioncurrency for the message : RetrieveExchangeRate
- Override the OutputParameter with the Exchange Rate value you want (the historical value in this scenario).
Here come the screenshots and examples :
The Opportunity Plugin (here on up update).
A bit of details, i have a field "be_exchangehistoricalvalue" where i store the old value from old / new opportunities Exchange Rate.
I make sure that the opportunity i'm update contains it and it's not null to use the ShareVariables i mentioned above.
It's a simple Key/Value entry, so you can give the name you want, and the value.
Now, let's focus on my plugin based on the transactioncurrency entity:
a. Before doing anything again, I make sure that my context contains the SharedVariables i set earlier from the ParentContext. This is mandatory as the plugin is triggered as a "child" plugin by the Opportunity plugin which set the Historical Exchange Rate in the SharedVariables. Without this ParentContext, you will always end up with a null value.
b. And as detailled in the steps above, I simply override the 'OutputParameters' of my TransactionCurrency plugin for the ExchangeRate. So when the plugin is done he thinks that the Exchange Rate which need to be used to recalculate the revenue fields will be the one you set. When i set the OutputParameters value you can see that to be able to access my SharedVariables i'm using the ParentContext same as in the "if" condition.
As seen above, we had the before update with the Exchange Rate to 1€ = 10$. Then after the update the Exchange Rate changed to 1€ = 5$. And now we will see (manually for the demo) the old Exchange Rate into the Historical field and see what happens :
In my currency entity, i still have the Exchange Rate set to 1€ = 5$ but you can see that my plugin override it with the value of my "historical Exchange Rate". Job done ! :-)
So this is it.
It seems to be really simple when you have the solution in front of you but of course, we can't know by heart all Messages there are in the CRM.
I hope i was clear enough and this will help you in your future migrations / developments.