23 February 2015

Rendering a Decimal into any Currency

A few days ago I faced an interesting challenge. One of our clients decided to enable multi-currency in the middle of the project and that wasn't discussed at the beginning. A couple of other developers from my team have built around 90% of the solution (unaware that multi-currency will be enabled at a later stage) and I got involved towards the end of the project. Part of the solution involved a multi-step wizard which includes a product search VisualForce page as well as a summary page before the end-user is redirected to a payment gateway - something similar to a shopping cart. The product records listed on those pages display mixed information that consists of a few objects linked through lookup fields. In order to make things easier and more dynamic, we've used a wrapper class that contains all the necessary information that we need to display. Pretty standard stuff when you hit this kind of complexity.

So, is there a way to render a Decimal variable into a specific currency format, keeping the conversion rate?

Enabling multi-currency should not cause any dramas since every object gets the CurrencyIsoCode field. So, with some minor tweaks you should be able to work it all out. However, when you need to do some manipulation on the amount e.g. apply tax rates dynamically based on other related data, as well as applying different types of discounts, it requires some apex logic. Referencing currency fields in apex become of type Decimal, so displaying these type of variables on your VisualForce page will result with just a number.

Result: 10

Of course we can format that number to any currency we want (note the $, you can put whatever symbol or currency you like here):

And viola we get: $10

But that does not mean that the value will get converted to the specified symbol of currency. Also, there is an alternative (proper) way to format the number to currency:

Which results with: $10

But how does VisualForce know which currency it needs to render this as? ...It's based on the current user's CurrencyIsoCode (if multi-currency is enabled for the org) or the user's locale (I think, correct me if I'm wrong, if muti-currency is not enabled).

All of the above doesn't help us display the value in the correct currency that is set on the record based on the CurrencyIsoCode field even if we know the amount and the code. If the original currency on the record is USD and the user's CurrencyIsoCode is AUD, there is no way we can display USD on the page unless we use <apex:outputField />. But we can't use that since we've done some manipulation on the amount (applied discounts, GST etc.). Here is a specific example of what I'm trying to say:

Let's assume we've got all the computer parts from the system (separate objects) and we have 1 wrapper class to combine them all so that we can easily display them on the VF page. Different parts have different currency that needs to be displayed to the user, as well as the conversion rate based on the user's currency. None of the methods described above can help us achieve the desired result, and I couldn't find any standard functionality that allows you to render the correct currency even though you have the amount and the currency ISO code, unless it's an <apex:outputField />.

So, I came up with this "hack" which might not be efficient but it does the job as it is supposed to. Essentially I'm using an <apex:outputField /> for each of the records, by creating a temporary record in memory, using a VF component and a controller:

It doesn't necessarily have to be an opportunity record, it can be any sObject Type (standard or custom) as long as the field is of type Currency. 

And boom, every record has the amount in the original currency and also the curren user's default currency based on the conversion rates (if the currencies are different).

If you have a better approach for this please let me know by leaving a comment.

No comments:

Post a Comment