Currency Conversion
in Multicurrency Org.g
In organizations with multicurrency enabled, sometimes we desperately
need a way to create formulas that convert an amount from one currency to
another using the current exchange rate configured in the system.
It is absolutely annoying to find that the currency
conversions are not made available for Salesforce formulas.
Given below is a sample scenario and the solution using a
small piece of Apex.
Scenario:
A multicurrency organization with many accounts.
The account
currency could be any of the active currencies.
Any account can have a number
of contracts associated with it. These contracts could be for any regions in
the world making it be in any currencies (also an active currency in the
system).
Imagine the Account is in USD and it has four different contracts; one
for Europe(in EUR), one for Japan (in JPY) , one for UK(in GBP) and one in USA
(in USD). Each of the individual contracts will display the contract values in
the records currency and in user currency; also possibly in the corporate currencies in
any reports.
But if you want to see the Total contracts' value of the all the 4
contracts on the account to see the Account's worth, it is not possible to create a roll up summary;
remember the Contract to Account relationship is just a look-up in Salesforce.
This demands that we need to convert each of the contract amounts from their
currencies to USD, which is the Account currency, in order to sum it up and
store it on the account record.
Solution:
Add trigger on the Contract to invoke the below given
trigger handler class that convert the currencies and store it on the account. This solution creates a map of currency and exchanges rates in the memory and uses it for every conversion. The convertCurrency method can be used in any similar situations for currency conversions.
PS: This code snippet shows only the update trigger. This has to
be extended for delete and undelete too. However, in case of the Contracts, an
Insert trigger is not needed as it the contract will be created as draft
always. So the update on the status will trigger the update trigger.
Contract Trigger:
trigger
ContractTrigger on Contract (after update) {
ContractTriggerHandler conTriggerHandler = new
ContractTriggerHandler();
}
if(trigger.isAfter &&
trigger.isUpdate){
conTriggerHandler.handleAfterUpdate(trigger.newMap,trigger.oldMap);
}
}
Trigger handler class.
public
class ContractTriggerHandler {
Map<String, Double>
CurrencyRates = new Map <String, Double>();
public ContractTriggerHandler() {
for (CurrencyType cRates : [SELECT
ISOCode, ConversionRate FROM CurrencyType WHERE IsActive=TRUE]) {
CurrencyRates.put(cRates.IsoCode,
cRates.ConversionRate);
}
}
public
void handleAfterUpdate(Map<id,Contract>
newMap,Map<id,Contract> oldMap){
List<Contract>
ConListToProcess = new List<Contract>();
for ( Id ContractId :
newMap.keySet() ){
if (
newMap.get(ContractId).Annual_Value__c !=
oldMap.get(ContractId).Annual_Value__c || newMap.get(ContractId).Status !=
oldMap.get(ContractId).Status) {
ConListToProcess.add(newMap.get(ContractId));
}
}
If(ConListToProcess.size() > 0)
updateAccountClassification(ConListToProcess);
}
public
void updateAccountClassification(List<Contract> ContractsList ){
Decimal TotalContractValue = 0;
Set<id> accIds = new
Set<id>();
List <Account> accListToUpdate
= new List <Account>();
for (Contract Contracstobject :
ContractsList) {
accIds.add(Contracstobject.AccountId);
}
List <Account> accList = new List
<Account> ([SELECT CurrencyIsoCode, Total_Contract_Value__c, OwnerId, (SELECT CurrencyIsoCode,Annual_Value__c from
Contracts where Status='Activated') from Account WHERE Id in :accIds]);
for( Account accObject: accList ) {
TotalContractValue = 0;
for (Contract contractlist :
accObject.Contracts) {
if
(contractlist.CurrencyIsoCode == accObject.CurrencyIsoCode) {
TotalContractValue
= TotalContractValue + contractlist.Annual_Value__c;
} else {
TotalContractValue
= TotalContractValue +
convertCurrency(contractlist.CurrencyIsoCode,accObject.CurrencyIsoCode,contractlist.Annual_Value__c);
}
}
accObject.Total_Contract_Value__c
= TotalContractValue;
}
accListToUpdate.add(accObject);
}
update
accListToUpdate;
}
public Double convertCurrency(String
inCurrency, String outCurrency, Decimal inAmount ) {
Double inCurrencyRate = CurrencyRates.get(inCurrency);
Double outCurrencyRate =
CurrencyRates.get(outCurrency);
Double amountInCorpCurr =
inAmount/inCurrencyRate;
Double outAmount = amountInCorpCurr
* outCurrencyRate;
return outAmount;
}
}
The key method here is convertCurrency.
This method has the following signature
public Double convertCurrency(String inCurrency, String outCurrency, Decimal inAmount ). The method accepts an InCurrency and OutCurrency and the Amount. It converts the Amount in InCurrency to an Amount in InOutCurrency and returns to the caller. This is done by converting the amount to the corporate currency and then converting the corporate currency to the OutCurrency.