Repository: killbill/killbill
Issue: Invoice formatter display wrong currency symbol

First of all, the code is using the locale to set the currency formatter. For instance in 
DefaultInvoiceFormatter:

```
 public String getFormattedPaidAmount() {
        final NumberFormat number = NumberFormat.getCurrencyInstance(locale);
        return number.format(getPaidAmount().doubleValue());
 }
```

The number format returned is based on the locale which is 'good' so it knows how to display the dots, comma, ... but wrong it comes to display the currency symbol.


Changed files:
invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java
invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java
invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java

diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
index 8ae278acfc..a3fed268b4 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatter.java
@@ -17,24 +17,22 @@
 package org.killbill.billing.invoice.template.formatters;
 
 import java.math.BigDecimal;
-import java.text.NumberFormat;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
+import java.util.Map;
 import java.util.UUID;
 
+import org.joda.money.CurrencyUnit;
 import org.joda.time.DateTime;
 import org.joda.time.LocalDate;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
 import org.killbill.billing.callcontext.InternalTenantContext;
-import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
-import org.killbill.billing.tenant.api.TenantInternalApi;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import org.killbill.billing.catalog.api.Currency;
 import org.killbill.billing.currency.api.CurrencyConversion;
 import org.killbill.billing.currency.api.CurrencyConversionApi;
@@ -45,17 +43,18 @@ import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.invoice.api.InvoicePayment;
 import org.killbill.billing.invoice.api.formatters.InvoiceFormatter;
+import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
 import org.killbill.billing.invoice.model.CreditAdjInvoiceItem;
 import org.killbill.billing.invoice.model.CreditBalanceAdjInvoiceItem;
 import org.killbill.billing.invoice.model.DefaultInvoice;
 import org.killbill.billing.util.template.translation.TranslatorConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableList;
 
-import static org.killbill.billing.util.DefaultAmountFormatter.round;
-
 /**
  * Format invoice fields
  */
@@ -70,8 +69,11 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
     private final CurrencyConversionApi currencyConversionApi;
     private final InternalTenantContext context;
     private final ResourceBundleFactory bundleFactory;
+    private Map<java.util.Currency, Locale> currencyLocaleMap;
 
-    public DefaultInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale, final CurrencyConversionApi currencyConversionApi, final ResourceBundleFactory bundleFactory, final InternalTenantContext context) {
+    public DefaultInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale,
+                                   final CurrencyConversionApi currencyConversionApi, final ResourceBundleFactory bundleFactory,
+                                   final InternalTenantContext context, Map<java.util.Currency, Locale> currencyLocaleMap) {
         this.config = config;
         this.invoice = invoice;
         this.dateFormatter = DateTimeFormat.mediumDate().withLocale(locale);
@@ -79,6 +81,7 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
         this.currencyConversionApi = currencyConversionApi;
         this.bundleFactory = bundleFactory;
         this.context = context;
+        this.currencyLocaleMap = currencyLocaleMap;
     }
 
     @Override
@@ -198,35 +201,56 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
 
     @Override
     public BigDecimal getChargedAmount() {
-        return round(Objects.firstNonNull(invoice.getChargedAmount(), BigDecimal.ZERO));
+        return Objects.firstNonNull(invoice.getChargedAmount(), BigDecimal.ZERO);
     }
 
     @Override
     public BigDecimal getOriginalChargedAmount() {
-        return round(Objects.firstNonNull(invoice.getOriginalChargedAmount(), BigDecimal.ZERO));
+        return Objects.firstNonNull(invoice.getOriginalChargedAmount(), BigDecimal.ZERO);
     }
 
     @Override
     public BigDecimal getBalance() {
-        return round(Objects.firstNonNull(invoice.getBalance(), BigDecimal.ZERO));
+        return Objects.firstNonNull(invoice.getBalance(), BigDecimal.ZERO);
     }
 
     @Override
     public String getFormattedChargedAmount() {
-        final NumberFormat number = NumberFormat.getCurrencyInstance(locale);
-        return number.format(getChargedAmount().doubleValue());
+        return getFormattedAmountByLocaleAndInvoiceCurrency(getChargedAmount());
     }
 
     @Override
     public String getFormattedPaidAmount() {
-        final NumberFormat number = NumberFormat.getCurrencyInstance(locale);
-        return number.format(getPaidAmount().doubleValue());
+        return getFormattedAmountByLocaleAndInvoiceCurrency(getPaidAmount());
     }
 
     @Override
     public String getFormattedBalance() {
-        final NumberFormat number = NumberFormat.getCurrencyInstance(locale);
-        return number.format(getBalance().doubleValue());
+        return getFormattedAmountByLocaleAndInvoiceCurrency(getBalance());
+    }
+
+    // Returns the formatted amount with the correct currency symbol that is get from the invoice currency.
+    private String getFormattedAmountByLocaleAndInvoiceCurrency(BigDecimal amount) {
+
+        String invoiceCurrencyCode = invoice.getCurrency().toString();
+        CurrencyUnit currencyUnit = CurrencyUnit.of(invoiceCurrencyCode);
+
+        final DecimalFormat numberFormatter = (DecimalFormat) DecimalFormat.getCurrencyInstance(locale);
+        DecimalFormatSymbols dfs = numberFormatter.getDecimalFormatSymbols();
+        dfs.setInternationalCurrencySymbol(currencyUnit.getCurrencyCode());
+
+        try {
+            final java.util.Currency currency = java.util.Currency.getInstance(invoiceCurrencyCode);
+            dfs.setCurrencySymbol(currency.getSymbol(currencyLocaleMap.get(currency)));
+        } catch (Exception e) {
+            dfs.setCurrencySymbol(currencyUnit.getSymbol(locale));
+        }
+
+        numberFormatter.setDecimalFormatSymbols(dfs);
+        numberFormatter.setMinimumFractionDigits(currencyUnit.getDefaultFractionDigits());
+        numberFormatter.setMaximumFractionDigits(currencyUnit.getDefaultFractionDigits());
+
+        return numberFormatter.format(amount.doubleValue());
     }
 
     @Override
@@ -288,7 +312,7 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
 
     @Override
     public BigDecimal getPaidAmount() {
-        return round(Objects.firstNonNull(invoice.getPaidAmount(), BigDecimal.ZERO));
+        return Objects.firstNonNull(invoice.getPaidAmount(), BigDecimal.ZERO);
     }
 
     @Override
@@ -337,13 +361,18 @@ public class DefaultInvoiceFormatter implements InvoiceFormatter {
         return invoice;
     }
 
+    @SuppressWarnings("UnusedDeclaration")
+    protected Map<java.util.Currency, Locale> getCurrencyLocaleMap() {
+        return currencyLocaleMap;
+    }
+
     @Override
     public BigDecimal getCreditedAmount() {
-        return round(Objects.firstNonNull(invoice.getCreditedAmount(), BigDecimal.ZERO));
+        return Objects.firstNonNull(invoice.getCreditedAmount(), BigDecimal.ZERO);
     }
 
     @Override
     public BigDecimal getRefundedAmount() {
-        return round(Objects.firstNonNull(invoice.getRefundedAmount(), BigDecimal.ZERO));
+        return Objects.firstNonNull(invoice.getRefundedAmount(), BigDecimal.ZERO);
     }
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java
index 890fb30338..6496df73f5 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceFormatterFactory.java
@@ -16,7 +16,10 @@
 
 package org.killbill.billing.invoice.template.formatters;
 
+import java.util.Currency;
+import java.util.HashMap;
 import java.util.Locale;
+import java.util.Map;
 
 import org.killbill.billing.callcontext.InternalTenantContext;
 import org.killbill.billing.currency.api.CurrencyConversionApi;
@@ -24,7 +27,6 @@ import org.killbill.billing.invoice.api.Invoice;
 import org.killbill.billing.invoice.api.formatters.InvoiceFormatter;
 import org.killbill.billing.invoice.api.formatters.InvoiceFormatterFactory;
 import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory;
-import org.killbill.billing.tenant.api.TenantInternalApi;
 import org.killbill.billing.util.template.translation.TranslatorConfig;
 
 public class DefaultInvoiceFormatterFactory implements InvoiceFormatterFactory {
@@ -32,6 +34,17 @@ public class DefaultInvoiceFormatterFactory implements InvoiceFormatterFactory {
     @Override
     public InvoiceFormatter createInvoiceFormatter(final TranslatorConfig config, final Invoice invoice, final Locale locale, CurrencyConversionApi currencyConversionApi,
                                                    final ResourceBundleFactory bundleFactory, final InternalTenantContext context) {
-        return new DefaultInvoiceFormatter(config, invoice, locale, currencyConversionApi, bundleFactory, context);
+
+        // this initialization relies on System.currentTimeMillis() instead of the Kill Bill clock (it won't be accurate when moving the clock)
+        Map<Currency, Locale> currencyLocaleMap = new HashMap<Currency, Locale>();
+        for (Locale localeItem : Locale.getAvailableLocales()) {
+            try {
+                java.util.Currency currency = java.util.Currency.getInstance(localeItem);
+                currencyLocaleMap.put(currency, localeItem);
+            }catch (Exception e){
+            }
+        }
+
+        return new DefaultInvoiceFormatter(config, invoice, locale, currencyConversionApi, bundleFactory, context, currencyLocaleMap);
     }
 }
diff --git a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
index 51ddcc637a..5516c8ca90 100644
--- a/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
+++ b/invoice/src/main/java/org/killbill/billing/invoice/template/formatters/DefaultInvoiceItemFormatter.java
@@ -36,14 +36,10 @@ import org.killbill.billing.util.LocaleUtils;
 import org.killbill.billing.util.template.translation.DefaultCatalogTranslator;
 import org.killbill.billing.util.template.translation.Translator;
 import org.killbill.billing.util.template.translation.TranslatorConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Strings;
 
-import static org.killbill.billing.util.DefaultAmountFormatter.round;
-
 /**
  * Format invoice item fields
  */
@@ -71,7 +67,7 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
 
     @Override
     public BigDecimal getAmount() {
-        return round(Objects.firstNonNull(item.getAmount(), BigDecimal.ZERO));
+        return Objects.firstNonNull(item.getAmount(), BigDecimal.ZERO);
     }
 
     @Override
@@ -168,7 +164,7 @@ public class DefaultInvoiceItemFormatter implements InvoiceItemFormatter {
 
     @Override
     public BigDecimal getRate() {
-        return round(BigDecimal.ZERO);
+        return BigDecimal.ZERO;
     }
 
     @Override
diff --git a/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java b/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java
index df0a9d7a08..6d5cc0afb0 100644
--- a/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java
+++ b/invoice/src/test/java/org/killbill/billing/invoice/template/formatters/TestDefaultInvoiceFormatter.java
@@ -34,7 +34,6 @@ import org.killbill.billing.invoice.api.InvoiceItem;
 import org.killbill.billing.invoice.api.InvoiceItemType;
 import org.killbill.billing.invoice.api.InvoicePaymentType;
 import org.killbill.billing.invoice.api.formatters.InvoiceFormatter;
-import org.killbill.billing.invoice.api.formatters.InvoiceFormatterFactory;
 import org.killbill.billing.invoice.api.formatters.ResourceBundleFactory.ResourceBundleType;
 import org.killbill.billing.invoice.model.CreditAdjInvoiceItem;
 import org.killbill.billing.invoice.model.CreditBalanceAdjInvoiceItem;
@@ -89,7 +88,7 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
         Assert.assertEquals(invoice.getCreditedAmount().doubleValue(), 0.00);
 
         // Verify the merge
-        final InvoiceFormatter formatter = new DefaultInvoiceFormatter(config, invoice, Locale.US, null, resourceBundleFactory, internalCallContext);
+        final InvoiceFormatter formatter = new DefaultInvoiceFormatter(config, invoice, Locale.US, null, resourceBundleFactory, internalCallContext, getAvailableLocales());
         final List<InvoiceItem> invoiceItems = formatter.getInvoiceItems();
         Assert.assertEquals(invoiceItems.size(), 1);
         Assert.assertEquals(invoiceItems.get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
@@ -143,7 +142,7 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
         Assert.assertEquals(invoice.getRefundedAmount().doubleValue(), -1.00);
 
         // Verify the merge
-        final InvoiceFormatter formatter = new DefaultInvoiceFormatter(config, invoice, Locale.US, null, resourceBundleFactory, internalCallContext);
+        final InvoiceFormatter formatter = new DefaultInvoiceFormatter(config, invoice, Locale.US, null, resourceBundleFactory, internalCallContext, getAvailableLocales());
         final List<InvoiceItem> invoiceItems = formatter.getInvoiceItems();
         Assert.assertEquals(invoiceItems.size(), 4);
         Assert.assertEquals(invoiceItems.get(0).getInvoiceItemType(), InvoiceItemType.FIXED);
@@ -160,7 +159,7 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
     public void testFormattedAmount() throws Exception {
         final FixedPriceInvoiceItem fixedItemEUR = new FixedPriceInvoiceItem(UUID.randomUUID(), UUID.randomUUID(), null, null,
                                                                              UUID.randomUUID().toString(), UUID.randomUUID().toString(),
-                                                                             new LocalDate(), new BigDecimal("1499.95"), Currency.EUR);
+                                                                             new LocalDate(), new BigDecimal("1499.952"), Currency.EUR);
         final Invoice invoiceEUR = new DefaultInvoice(UUID.randomUUID(), new LocalDate(), new LocalDate(), Currency.EUR);
         invoiceEUR.addInvoiceItem(fixedItemEUR);
 
@@ -186,6 +185,158 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
                     Locale.FRANCE);
     }
 
+    @Test(groups = "fast")
+    public void testFormattedAmountFranceAndJPY() throws Exception {
+
+        final FixedPriceInvoiceItem fixedItem = new FixedPriceInvoiceItem(UUID.randomUUID(), UUID.randomUUID(), null, null,
+                                                                             UUID.randomUUID().toString(), UUID.randomUUID().toString(),
+                                                                             new LocalDate(), new BigDecimal("1500.00"), Currency.JPY);
+        final Invoice invoice = new DefaultInvoice(UUID.randomUUID(), new LocalDate(), new LocalDate(), Currency.JPY);
+        invoice.addInvoiceItem(fixedItem);
+
+        checkOutput(invoice,
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedChargedAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedPaidAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedBalance}}</strong></td>\\n" +
+                    "</tr>",
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>1 500 ￥</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>0 ￥</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>1 500 ￥</strong></td>\\n" +
+                    "</tr>",
+                    Locale.FRANCE);
+    }
+
+    @Test(groups = "fast")
+    public void testFormattedAmountUSAndBTC() throws Exception {
+
+        final FixedPriceInvoiceItem fixedItem = new FixedPriceInvoiceItem(UUID.randomUUID(), UUID.randomUUID(), null, null,
+                                                                          UUID.randomUUID().toString(), UUID.randomUUID().toString(),
+                                                                          new LocalDate(), new BigDecimal("1105.28843439"), Currency.BTC);
+        final Invoice invoice = new DefaultInvoice(UUID.randomUUID(), new LocalDate(), new LocalDate(), Currency.BTC);
+        invoice.addInvoiceItem(fixedItem);
+
+        checkOutput(invoice,
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedChargedAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedPaidAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedBalance}}</strong></td>\\n" +
+                    "</tr>",
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>BTC1,105.28843439</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>BTC0.00000000</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>BTC1,105.28843439</strong></td>\\n" +
+                    "</tr>",
+                    Locale.US);
+    }
+
+    @Test(groups = "fast")
+    public void testFormattedAmountUSAndEUR() throws Exception {
+        final FixedPriceInvoiceItem fixedItem = new FixedPriceInvoiceItem(UUID.randomUUID(), UUID.randomUUID(), null, null,
+                                                                             UUID.randomUUID().toString(), UUID.randomUUID().toString(),
+                                                                             new LocalDate(), new BigDecimal("2635.14"), Currency.EUR);
+        final Invoice invoice = new DefaultInvoice(UUID.randomUUID(), new LocalDate(), new LocalDate(), Currency.EUR);
+        invoice.addInvoiceItem(fixedItem);
+
+        checkOutput(invoice,
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedChargedAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedPaidAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedBalance}}</strong></td>\\n" +
+                    "</tr>",
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>€2,635.14</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>€0.00</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>€2,635.14</strong></td>\\n" +
+                    "</tr>",
+                    Locale.US);
+    }
+
+    @Test(groups = "fast")
+    public void testFormattedAmountUSAndBRL() throws Exception {
+        final FixedPriceInvoiceItem fixedItem = new FixedPriceInvoiceItem(UUID.randomUUID(), UUID.randomUUID(), null, null,
+                                                                             UUID.randomUUID().toString(), UUID.randomUUID().toString(),
+                                                                             new LocalDate(), new BigDecimal("2635.14"), Currency.BRL);
+        final Invoice invoice = new DefaultInvoice(UUID.randomUUID(), new LocalDate(), new LocalDate(), Currency.BRL);
+        invoice.addInvoiceItem(fixedItem);
+
+        checkOutput(invoice,
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedChargedAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedPaidAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedBalance}}</strong></td>\\n" +
+                    "</tr>",
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>R$2,635.14</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>R$0.00</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>R$2,635.14</strong></td>\\n" +
+                    "</tr>",
+                    Locale.US);
+    }
+
+    @Test(groups = "fast")
+    public void testFormattedAmountUSAndGBP() throws Exception {
+        final FixedPriceInvoiceItem fixedItem = new FixedPriceInvoiceItem(UUID.randomUUID(), UUID.randomUUID(), null, null,
+                                                                             UUID.randomUUID().toString(), UUID.randomUUID().toString(),
+                                                                             new LocalDate(), new BigDecimal("1499.95"), Currency.GBP);
+        final Invoice invoice = new DefaultInvoice(UUID.randomUUID(), new LocalDate(), new LocalDate(), Currency.GBP);
+        invoice.addInvoiceItem(fixedItem);
+
+        checkOutput(invoice,
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedChargedAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedPaidAmount}}</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>{{invoice.formattedBalance}}</strong></td>\\n" +
+                    "</tr>",
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>£1,499.95</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>£0.00</strong></td>\\n" +
+                    "</tr>\\n" +
+                    "<tr>\\n" +
+                    "    <td class=\\"amount\\"><strong>£1,499.95</strong></td>\\n" +
+                    "</tr>",
+                    Locale.US);
+    }
+
     @Test(groups = "fast")
     public void testProcessedCurrencyExists() throws Exception {
         final Invoice invoice = new DefaultInvoice(UUID.randomUUID(), clock.getUTCNow(), UUID.randomUUID(), new Integer(234), new LocalDate(), new LocalDate(), Currency.BRL, Currency.USD, false);
@@ -329,7 +480,7 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
 
         data.put("text", translator);
 
-        data.put("invoice", new DefaultInvoiceFormatter(config, invoice, Locale.US, currencyConversionApi, resourceBundleFactory, internalCallContext));
+        data.put("invoice", new DefaultInvoiceFormatter(config, invoice, Locale.US, currencyConversionApi, resourceBundleFactory, internalCallContext, getAvailableLocales()));
 
         final String formattedText = templateEngine.executeTemplateText(template, data);
 
@@ -338,9 +489,23 @@ public class TestDefaultInvoiceFormatter extends InvoiceTestSuiteNoDB {
 
     private void checkOutput(final Invoice invoice, final String template, final String expected, final Locale locale) {
         final Map<String, Object> data = new HashMap<String, Object>();
-        data.put("invoice", new DefaultInvoiceFormatter(config, invoice, locale, null, resourceBundleFactory, internalCallContext));
+        data.put("invoice", new DefaultInvoiceFormatter(config, invoice, locale, null, resourceBundleFactory, internalCallContext, getAvailableLocales()));
 
         final String formattedText = templateEngine.executeTemplateText(template, data);
         Assert.assertEquals(formattedText, expected);
     }
+
+    private Map<java.util.Currency, Locale> getAvailableLocales() {
+        Map<java.util.Currency, Locale> currencyLocaleMap = new HashMap<java.util.Currency, Locale>();
+
+        currencyLocaleMap.put(java.util.Currency.getInstance(Locale.US), Locale.US);
+        currencyLocaleMap.put(java.util.Currency.getInstance(Locale.FRANCE), Locale.FRANCE);
+        currencyLocaleMap.put(java.util.Currency.getInstance(Locale.JAPAN), Locale.JAPAN);
+        currencyLocaleMap.put(java.util.Currency.getInstance(Locale.UK), Locale.UK);
+        Locale brLocale = new Locale("pt", "BR");
+        currencyLocaleMap.put(java.util.Currency.getInstance(brLocale), brLocale);
+
+        return currencyLocaleMap;
+    }
+
 }