I am currently starting a refactor of a small application that only handles two currencies but I do not really like how I implemented it. Basically what I did was pretty naive… I just added a boolean currency type and another field with conversion rates. This led to some trouble when user tried to use documents of different currencies for math operations.
I also save the amounts in normal formats (example: 000,000.00) but I have seen some posts suggesting using cents.
On the other side of things, one a document starts its lifecycle with a currency, everything related to it must be in the same currency with out the user having to specify the currency.
So anyone suggest a better approach for handling multi-currency?
You might want to read this post regarding money libraries (I am the author of one of them).
A couple of basic thoughts on money handling:
Unless you are completely in control of the currencies in use and you are very familiar with different currency rules (number of decimal places for example - currencies have any of 0, 1, 2, 3 or four places) use Decimal. Using integers means you still need to track decimal places unless you can guarantee all currencies you are using use the same decimal digits.
Always tag the money amount with its currency. A tagged tuple like {:AUD, 1234} is fine, or a struct (which is what libraries usually use) and only ever do operations on the structure. Over time you’ll want to trace how money amounts are transformed and create some guarantees - for example you want to guarantee you don’t add two money amounts together in different currencies.
Use ISO4217 currency codes so that you can interchange with other apps and users easily and have no confusion on what is meant. Tag your document with the ISO4217 code per your described use case.
Always do money calculations at maximum precision and round only when you need a final result. This is how financial apps work, typically at a precision of at least 7 digits. Another reason to use Decimal is to allow arbitrary arithmetic calculations.
Be aware that different currencies have rounding rules different for cash amounts than accounting amounts. For example, the Australia dollar cash amount rounds to the nearest 5c whereas the accounting amount rounds to the cent.
If you need to serialize money amounts (for example to a database), I recommend using a composite type in Postgres so that the currency is always associated with the amount.
I just started implementing ex_money and I feel like the authors are holding my hand and spoon feeding me how to implement an app that works with money
I think its one of the best libs I’ve had the pleasure of using for a domain I didn’t know well going into it.