diff --git a/afterpay/src/main/kotlin/com/afterpay/android/Afterpay.kt b/afterpay/src/main/kotlin/com/afterpay/android/Afterpay.kt index 18c13fb7..b996a277 100644 --- a/afterpay/src/main/kotlin/com/afterpay/android/Afterpay.kt +++ b/afterpay/src/main/kotlin/com/afterpay/android/Afterpay.kt @@ -27,14 +27,6 @@ object Afterpay { internal val locale: Locale get() = configuration?.locale ?: Locales.US - private val validLocaleCountries = setOf( - Locales.AUSTRALIA.country, - Locales.CANADA.country, - Locales.UK.country, - Locales.NEW_ZEALAND.country, - Locales.US.country - ) - /** * Creates an [Intent] that can be used to initiate an Afterpay transaction. Provide the * new [Intent] in [startActivityForResult][android.app.Activity.startActivityForResult] @@ -104,10 +96,13 @@ object Afterpay { throw IllegalArgumentException("Minimum order amount is invalid") } } - if (!validLocaleCountries.contains(configuration.locale.country)) { + + val validCountries = Locales.validSet.map { it.country } + + if (!validCountries.contains(configuration.locale.country)) { throw IllegalArgumentException( "Locale contains an unsupported country: ${configuration.locale.country}. " + - "Supported countries include: ${validLocaleCountries.joinToString(",")}" + "Supported countries include: ${validCountries.joinToString(",")}" ) } } diff --git a/afterpay/src/main/kotlin/com/afterpay/android/internal/AfterpayInstalment.kt b/afterpay/src/main/kotlin/com/afterpay/android/internal/AfterpayInstalment.kt index b6116138..a49ed233 100644 --- a/afterpay/src/main/kotlin/com/afterpay/android/internal/AfterpayInstalment.kt +++ b/afterpay/src/main/kotlin/com/afterpay/android/internal/AfterpayInstalment.kt @@ -1,10 +1,10 @@ package com.afterpay.android.internal -import com.afterpay.android.Afterpay import java.math.BigDecimal import java.math.RoundingMode import java.text.DecimalFormat import java.text.NumberFormat +import java.util.Currency internal sealed class AfterpayInstalment { data class Available( @@ -19,19 +19,35 @@ internal sealed class AfterpayInstalment { object NoConfiguration : AfterpayInstalment() companion object { - fun of(totalCost: BigDecimal): AfterpayInstalment { - val configuration = Afterpay.configuration ?: return NoConfiguration - - val currencyFormatter = (NumberFormat.getCurrencyInstance() as DecimalFormat).apply { - currency = configuration.currency - decimalFormatSymbols = decimalFormatSymbols.apply { - currencySymbol = when (configuration.currency.currencyCode) { - "AUD" -> "A$" - "NZD" -> "NZ$" - "CAD" -> "CA$" - else -> "$" + fun of(totalCost: BigDecimal, configuration: Configuration?): AfterpayInstalment { + if (configuration == null) { + return NoConfiguration + } + + val currencyLocale = Locales.validSet.first { Currency.getInstance(it) == configuration.currency } + val currencySymbol = configuration.currency.getSymbol(currencyLocale) + val usCurrencySymbol = Currency.getInstance(Locales.US).getSymbol(Locales.US) + val localCurrency = Currency.getInstance(configuration.locale) + + val currencyFormatter = (NumberFormat.getCurrencyInstance(currencyLocale) as DecimalFormat).apply { + this.currency = configuration.currency + } + + if (configuration.locale == Locales.US) { + currencyFormatter.apply { + decimalFormatSymbols = decimalFormatSymbols.apply { + this.currencySymbol = when (configuration.currency) { + Currency.getInstance(Locales.AUSTRALIA) -> "A$" + Currency.getInstance(Locales.NEW_ZEALAND) -> "NZ$" + Currency.getInstance(Locales.CANADA) -> "CA$" + else -> currencySymbol + } } } + } else if (currencySymbol == usCurrencySymbol && configuration.currency != localCurrency) { + currencyFormatter.apply { + this.applyPattern("¤#,##0.00 ¤¤") + } } val minimumAmount = configuration.minimumAmount ?: BigDecimal.ZERO diff --git a/afterpay/src/main/kotlin/com/afterpay/android/internal/Locales.kt b/afterpay/src/main/kotlin/com/afterpay/android/internal/Locales.kt index 212b75a8..fb99735d 100644 --- a/afterpay/src/main/kotlin/com/afterpay/android/internal/Locales.kt +++ b/afterpay/src/main/kotlin/com/afterpay/android/internal/Locales.kt @@ -2,11 +2,13 @@ package com.afterpay.android.internal import java.util.Locale -object Locales { +internal object Locales { val AUSTRALIA = Locale("en", "AU") - val CANADA = Locale.CANADA + val CANADA: Locale = Locale.CANADA val NEW_ZEALAND = Locale("en", "NZ") - val UK = Locale.UK - val US = Locale.US + val UK: Locale = Locale.UK + val US: Locale = Locale.US + + val validSet = setOf(AUSTRALIA, CANADA, UK, NEW_ZEALAND, US) } diff --git a/afterpay/src/main/kotlin/com/afterpay/android/view/AfterpayPriceBreakdown.kt b/afterpay/src/main/kotlin/com/afterpay/android/view/AfterpayPriceBreakdown.kt index f4b30db7..95500545 100644 --- a/afterpay/src/main/kotlin/com/afterpay/android/view/AfterpayPriceBreakdown.kt +++ b/afterpay/src/main/kotlin/com/afterpay/android/view/AfterpayPriceBreakdown.kt @@ -106,7 +106,7 @@ class AfterpayPriceBreakdown(context: Context, attrs: AttributeSet?) : FrameLayo setBounds(0, 0, drawableWidth.toInt(), drawableHeight.toInt()) } - val instalment = AfterpayInstalment.of(totalAmount) + val instalment = AfterpayInstalment.of(totalAmount, Afterpay.configuration) val content = generateContent(instalment) textView.apply { diff --git a/afterpay/src/test/kotlin/com/afterpay/android/AfterpayInstalmentTest.kt b/afterpay/src/test/kotlin/com/afterpay/android/AfterpayInstalmentTest.kt new file mode 100644 index 00000000..cdc2be4b --- /dev/null +++ b/afterpay/src/test/kotlin/com/afterpay/android/AfterpayInstalmentTest.kt @@ -0,0 +1,114 @@ +package com.afterpay.android + +import com.afterpay.android.internal.AfterpayInstalment +import com.afterpay.android.internal.Configuration +import com.afterpay.android.internal.Locales +import org.junit.Assert.assertEquals +import org.junit.Test +import java.math.BigDecimal +import java.util.Currency +import java.util.Locale + +class AfterpayInstalmentTest { + private val australianDollar: Currency = Currency.getInstance("AUD") + private val canadianDollar: Currency = Currency.getInstance("CAD") + private val poundSterling: Currency = Currency.getInstance("GBP") + private val newZealandDollar: Currency = Currency.getInstance("NZD") + private val unitedStatesDollar: Currency = Currency.getInstance("USD") + + private val oneHundredAndTwenty = 120.toBigDecimal() + + @Test + fun `available instalment in Australia locale`() { + val locale = Locales.AUSTRALIA + + val audInstalment = availableInstalment(oneHundredAndTwenty, australianDollar, locale) + val cadInstalment = availableInstalment(oneHundredAndTwenty, canadianDollar, locale) + val gbpInstalment = availableInstalment(oneHundredAndTwenty, poundSterling, locale) + val nzdInstalment = availableInstalment(oneHundredAndTwenty, newZealandDollar, locale) + val usdInstalment = availableInstalment(oneHundredAndTwenty, unitedStatesDollar, locale) + + assertEquals("$30.00", audInstalment.instalmentAmount) + assertEquals("$30.00 CAD", cadInstalment.instalmentAmount) + assertEquals("£30.00", gbpInstalment.instalmentAmount) + assertEquals("$30.00 NZD", nzdInstalment.instalmentAmount) + assertEquals("$30.00 USD", usdInstalment.instalmentAmount) + } + + @Test + fun `available instalment in Canada locale`() { + val locale = Locales.CANADA + + val audInstalment = availableInstalment(oneHundredAndTwenty, australianDollar, locale) + val cadInstalment = availableInstalment(oneHundredAndTwenty, canadianDollar, locale) + val gbpInstalment = availableInstalment(oneHundredAndTwenty, poundSterling, locale) + val nzdInstalment = availableInstalment(oneHundredAndTwenty, newZealandDollar, locale) + val usdInstalment = availableInstalment(oneHundredAndTwenty, unitedStatesDollar, locale) + + assertEquals("$30.00 AUD", audInstalment.instalmentAmount) + assertEquals("$30.00", cadInstalment.instalmentAmount) + assertEquals("£30.00", gbpInstalment.instalmentAmount) + assertEquals("$30.00 NZD", nzdInstalment.instalmentAmount) + assertEquals("$30.00 USD", usdInstalment.instalmentAmount) + } + + @Test + fun `available instalment in UK locale`() { + val locale = Locales.UK + + val audInstalment = availableInstalment(oneHundredAndTwenty, australianDollar, locale) + val cadInstalment = availableInstalment(oneHundredAndTwenty, canadianDollar, locale) + val gbpInstalment = availableInstalment(oneHundredAndTwenty, poundSterling, locale) + val nzdInstalment = availableInstalment(oneHundredAndTwenty, newZealandDollar, locale) + val usdInstalment = availableInstalment(oneHundredAndTwenty, unitedStatesDollar, locale) + + assertEquals("$30.00 AUD", audInstalment.instalmentAmount) + assertEquals("$30.00 CAD", cadInstalment.instalmentAmount) + assertEquals("£30.00", gbpInstalment.instalmentAmount) + assertEquals("$30.00 NZD", nzdInstalment.instalmentAmount) + assertEquals("$30.00 USD", usdInstalment.instalmentAmount) + } + + @Test + fun `available instalment in New Zealand locale`() { + val locale = Locales.NEW_ZEALAND + + val audInstalment = availableInstalment(oneHundredAndTwenty, australianDollar, locale) + val cadInstalment = availableInstalment(oneHundredAndTwenty, canadianDollar, locale) + val gbpInstalment = availableInstalment(oneHundredAndTwenty, poundSterling, locale) + val nzdInstalment = availableInstalment(oneHundredAndTwenty, newZealandDollar, locale) + val usdInstalment = availableInstalment(oneHundredAndTwenty, unitedStatesDollar, locale) + + assertEquals("$30.00 AUD", audInstalment.instalmentAmount) + assertEquals("$30.00 CAD", cadInstalment.instalmentAmount) + assertEquals("£30.00", gbpInstalment.instalmentAmount) + assertEquals("$30.00", nzdInstalment.instalmentAmount) + assertEquals("$30.00 USD", usdInstalment.instalmentAmount) + } + + @Test + fun `available instalment in US locale`() { + val locale = Locales.US + + val audInstalment = availableInstalment(oneHundredAndTwenty, australianDollar, locale) + val cadInstalment = availableInstalment(oneHundredAndTwenty, canadianDollar, locale) + val gbpInstalment = availableInstalment(oneHundredAndTwenty, poundSterling, locale) + val nzdInstalment = availableInstalment(oneHundredAndTwenty, newZealandDollar, locale) + val usdInstalment = availableInstalment(oneHundredAndTwenty, unitedStatesDollar, locale) + + assertEquals("A$30.00", audInstalment.instalmentAmount) + assertEquals("CA$30.00", cadInstalment.instalmentAmount) + assertEquals("£30.00", gbpInstalment.instalmentAmount) + assertEquals("NZ$30.00", nzdInstalment.instalmentAmount) + assertEquals("$30.00", usdInstalment.instalmentAmount) + } + + private fun availableInstalment( + amount: BigDecimal, + currency: Currency, + locale: Locale + ): AfterpayInstalment.Available { + val configuration = Configuration(50.toBigDecimal(), 1000.toBigDecimal(), currency, locale) + return AfterpayInstalment.of(amount, configuration) as AfterpayInstalment.Available + } +}