diff --git a/CHANGELOG.md b/CHANGELOG.md
index 478e337b60b..c355c389306 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
### PaymentSheet
* [ADDED][7198](https://github.com/stripe/stripe-android/pull/7198) PaymentSheet now supports GrabPay for PaymentIntents.
+* [ADDED][7214](https://github.com/stripe/stripe-android/pull/7214) PaymentSheet now supports FPX for PaymentIntents.
* [ADDED][7199](https://github.com/stripe/stripe-android/pull/7199) PaymentSheet now supports AmazonPay for PaymentIntents in private beta.
* [CHANGED][7144](https://github.com/stripe/stripe-android/pull/7144) PaymentSheet now features rounded corners with the radius provided in `PaymentSheet.Shapes.cornerRadiusDp`.
* [FIXED][7190](https://github.com/stripe/stripe-android/pull/7190) Fixed an issue where amounts in Laotian Kip were displayed incorrectly.
diff --git a/payments-ui-core/res/drawable/stripe_ic_paymentsheet_pm_fpx.xml b/payments-ui-core/res/drawable/stripe_ic_paymentsheet_pm_fpx.xml
new file mode 100644
index 00000000000..33bad3012c9
--- /dev/null
+++ b/payments-ui-core/res/drawable/stripe_ic_paymentsheet_pm_fpx.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/payments-ui-core/res/values/donottranslate.xml b/payments-ui-core/res/values/donottranslate.xml
index a5d7aac9b1c..c307b03b4c4 100644
--- a/payments-ui-core/res/values/donottranslate.xml
+++ b/payments-ui-core/res/values/donottranslate.xml
@@ -15,6 +15,7 @@
UPI
Cash App Pay
GrabPay
+ FPX Bank
Affirm
Revolut Pay
diff --git a/payments-ui-core/src/main/assets/lpms.json b/payments-ui-core/src/main/assets/lpms.json
index 49c6dc21699..edbabcc438f 100644
--- a/payments-ui-core/src/main/assets/lpms.json
+++ b/payments-ui-core/src/main/assets/lpms.json
@@ -841,8 +841,116 @@
"async": false,
"fields": [],
"selector_icon": {
- "light_theme_png": "https://js.stripe.com/v3/fingerprinted/img/payment-methods/icon-pm-grabpay@3x-e54da1d788668a5909e4801d5c243198.png",
- "light_theme_svg": "https://js.stripe.com/v3/fingerprinted/img/payment-methods/icon-pm-grabpay-97ee78fdbbf1890bdf19986e997e685d.svg"
+ "light_theme_png": "https://js.stripe.com/v3/fingerprinted/img/payment-methods/icon-pm-grabpay@3x-e54da1d788668a5909e4801d5c243198.png"
+ }
+ },
+ {
+ "type": "fpx",
+ "async": false,
+ "selector_icon": {
+ "light_theme_png": "https://js.stripe.com/v3/fingerprinted/img/payment-methods/icon-pm-fpx@3x-305453711338125d9cb4f86ff866ba6a.png"
+ },
+ "fields": [
+ {
+ "type": "selector",
+ "translation_id": "upe.labels.fpx.bank",
+ "items": [
+ {
+ "display_text": "Affin Bank",
+ "api_value": "affin_bank"
+ },
+ {
+ "display_text": "Alliance Bank",
+ "api_value": "alliance_bank"
+ },
+ {
+ "display_text": "AmBank",
+ "api_value": "ambank"
+ },
+ {
+ "display_text": "Bank Islam",
+ "api_value": "bank_islam"
+ },
+ {
+ "display_text": "Bank Muamalat",
+ "api_value": "bank_muamalat"
+ },
+ {
+ "display_text": "Bank Rakyat",
+ "api_value": "bank_rakyat"
+ },
+ {
+ "display_text": "BSN",
+ "api_value": "bsn"
+ },
+ {
+ "display_text": "CIMB Clicks",
+ "api_value": "cimb"
+ },
+ {
+ "display_text": "Hong Leong Bank",
+ "api_value": "hong_leong_bank"
+ },
+ {
+ "display_text": "HSBC BANK",
+ "api_value": "hsbc"
+ },
+ {
+ "display_text": "KFH",
+ "api_value": "kfh"
+ },
+ {
+ "display_text": "Maybank2E",
+ "api_value": "maybank2e"
+ },
+ {
+ "display_text": "Maybank2U",
+ "api_value": "maybank2u"
+ },
+ {
+ "display_text": "OCBC Bank",
+ "api_value": "ocbc"
+ },
+ {
+ "display_text": "Public Bank",
+ "api_value": "public_bank"
+ },
+ {
+ "display_text": "RHB Bank",
+ "api_value": "rhb"
+ },
+ {
+ "display_text": "Standard Chartered",
+ "api_value": "standard_chartered"
+ },
+ {
+ "display_text": "UOB Bank",
+ "api_value": "uob"
+ }
+ ],
+ "api_path": {
+ "v1": "fpx[bank]"
+ }
+ },
+ {
+ "type": "placeholder",
+ "for": "billing_address"
+ }
+ ],
+ "next_action_spec": {
+ "confirm_response_status_specs": {
+ "requires_action": {
+ "type": "redirect_to_url"
+ }
+ },
+ "post_confirm_handling_pi_status_specs": {
+ "succeeded": {
+ "type": "finished"
+ },
+ "requires_action": {
+ "type": "canceled"
+ }
+ }
}
}
]
diff --git a/payments-ui-core/src/main/java/com/stripe/android/paymentsheet/forms/PaymentMethodRequirements.kt b/payments-ui-core/src/main/java/com/stripe/android/paymentsheet/forms/PaymentMethodRequirements.kt
index d3cd2ea9366..0f838f19eac 100644
--- a/payments-ui-core/src/main/java/com/stripe/android/paymentsheet/forms/PaymentMethodRequirements.kt
+++ b/payments-ui-core/src/main/java/com/stripe/android/paymentsheet/forms/PaymentMethodRequirements.kt
@@ -331,3 +331,9 @@ internal val GrabPayRequirement = PaymentMethodRequirements(
siRequirements = null,
confirmPMFromCustomer = false,
)
+
+internal val FpxRequirement = PaymentMethodRequirements(
+ piRequirements = emptySet(),
+ siRequirements = null,
+ confirmPMFromCustomer = false,
+)
diff --git a/payments-ui-core/src/main/java/com/stripe/android/ui/core/elements/TranslationId.kt b/payments-ui-core/src/main/java/com/stripe/android/ui/core/elements/TranslationId.kt
index 59522f1da2c..e6de702394d 100644
--- a/payments-ui-core/src/main/java/com/stripe/android/ui/core/elements/TranslationId.kt
+++ b/payments-ui-core/src/main/java/com/stripe/android/ui/core/elements/TranslationId.kt
@@ -20,6 +20,9 @@ enum class TranslationId(val resourceId: Int) {
@SerialName("upe.labels.eps.bank")
EpsBank(R.string.stripe_eps_bank),
+ @SerialName("upe.labels.fpx.bank")
+ FpxBank(R.string.stripe_fpx_bank),
+
@SerialName("address.label.name")
AddressName(CoreR.string.stripe_address_label_full_name),
diff --git a/payments-ui-core/src/main/java/com/stripe/android/ui/core/forms/resources/LpmRepository.kt b/payments-ui-core/src/main/java/com/stripe/android/ui/core/forms/resources/LpmRepository.kt
index b6ef5271174..ac3389e4d46 100644
--- a/payments-ui-core/src/main/java/com/stripe/android/ui/core/forms/resources/LpmRepository.kt
+++ b/payments-ui-core/src/main/java/com/stripe/android/ui/core/forms/resources/LpmRepository.kt
@@ -22,6 +22,7 @@ import com.stripe.android.paymentsheet.forms.BancontactRequirement
import com.stripe.android.paymentsheet.forms.CardRequirement
import com.stripe.android.paymentsheet.forms.CashAppPayRequirement
import com.stripe.android.paymentsheet.forms.EpsRequirement
+import com.stripe.android.paymentsheet.forms.FpxRequirement
import com.stripe.android.paymentsheet.forms.GiropayRequirement
import com.stripe.android.paymentsheet.forms.GrabPayRequirement
import com.stripe.android.paymentsheet.forms.IdealRequirement
@@ -95,6 +96,7 @@ class LpmRepository constructor(
PaymentMethod.Type.Upi.code,
PaymentMethod.Type.CashAppPay.code,
PaymentMethod.Type.GrabPay.code,
+ PaymentMethod.Type.Fpx.code,
)
}
@@ -529,6 +531,18 @@ class LpmRepository constructor(
requirement = GrabPayRequirement,
formSpec = LayoutSpec(sharedDataSpec.fields),
)
+ PaymentMethod.Type.Fpx.code -> SupportedPaymentMethod(
+ code = "fpx",
+ requiresMandate = false,
+ mandateRequirement = MandateRequirement.Never,
+ displayNameResource = R.string.stripe_paymentsheet_payment_method_fpx,
+ iconResource = R.drawable.stripe_ic_paymentsheet_pm_fpx,
+ lightThemeIconUrl = sharedDataSpec.selectorIcon?.lightThemePng,
+ darkThemeIconUrl = sharedDataSpec.selectorIcon?.darkThemePng,
+ tintIconOnSelection = false,
+ requirement = FpxRequirement,
+ formSpec = LayoutSpec(sharedDataSpec.fields),
+ )
else -> null
}
diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestFpx.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestFpx.kt
new file mode 100644
index 00000000000..9508162d6df
--- /dev/null
+++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestFpx.kt
@@ -0,0 +1,32 @@
+package com.stripe.android.lpm
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.stripe.android.BaseLpmTest
+import com.stripe.android.test.core.Automatic
+import com.stripe.android.test.core.Currency
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+internal class TestFpx : BaseLpmTest() {
+ private val fpx = newUser.copy(
+ paymentMethod = lpmRepository.fromCode("fpx")!!,
+ currency = Currency.MYR,
+ merchantCountryCode = "MY",
+ automatic = Automatic.On,
+ )
+
+ @Test
+ fun testFpx() {
+ testDriver.confirmNewOrGuestComplete(
+ testParameters = fpx,
+ )
+ }
+
+ @Test
+ fun testFpxInCustomFlow() {
+ testDriver.confirmCustom(
+ testParameters = fpx,
+ )
+ }
+}
diff --git a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/TestParameters.kt b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/TestParameters.kt
index 40a410e4949..3f37d4fb259 100644
--- a/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/TestParameters.kt
+++ b/paymentsheet-example/src/androidTest/java/com/stripe/android/test/core/TestParameters.kt
@@ -121,6 +121,7 @@ enum class Currency {
GBP,
INR,
SGD,
+ MYR,
}
/**
diff --git a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/activity/PaymentSheetPlaygroundActivity.kt b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/activity/PaymentSheetPlaygroundActivity.kt
index 564ea219e69..71bdd33a2ce 100644
--- a/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/activity/PaymentSheetPlaygroundActivity.kt
+++ b/paymentsheet-example/src/main/java/com/stripe/android/paymentsheet/example/playground/activity/PaymentSheetPlaygroundActivity.kt
@@ -882,7 +882,7 @@ class PaymentSheetPlaygroundActivity : AppCompatActivity() {
/**
* Modify this list if you want to change the countries displayed in the playground.
*/
- country.code.value in setOf("US", "GB", "AU", "FR", "IN", "SG")
+ country.code.value in setOf("US", "GB", "AU", "FR", "IN", "SG", "MY")
}.map { country ->
/**
* Modify this statement to change the default currency associated with each
@@ -907,6 +907,9 @@ class PaymentSheetPlaygroundActivity : AppCompatActivity() {
"SG" -> {
country to "SGD"
}
+ "MY" -> {
+ country to "MYR"
+ }
else -> {
country to "USD"
}
@@ -915,18 +918,6 @@ class PaymentSheetPlaygroundActivity : AppCompatActivity() {
// List was created from: https://stripe.com/docs/currencies
/** Modify this list if you want to change the currencies displayed in the playground **/
- private val stripeSupportedCurrencies = listOf("AUD", "EUR", "GBP", "USD", "INR", "PLN", "SGD")
-// "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AWG", "AZN", "BAM",
-// "BBD", "BDT", "BGN", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BWP", "BYN", "BZD",
-// "CAD", "CDF", "CHF", "CLP", "CNY", "COP", "CRC", "CVE", "CZK", "DJF", "DKK", "DOP",
-// "DZD", "EGP", "ETB", "FJD", "FKP", "GEL", "GIP", "GMD", "GNF", "GTQ",
-// "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "ISK", "JMD", "JPY",
-// "KES", "KGS", "KHR", "KMF", "KRW", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL",
-// "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MUR", "MVR", "MWK", "MXN",
-// "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "PAB", "PEN", "PGK", "PHP",
-// "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SEK",
-// "SGD", "SHP", "SLL", "SOS", "SRD", "STD", "SZL", "THB", "TJS", "TOP", "TRY", "TTD",
-// "TWD", "TZS", "UAH", "UGX", "UYU", "UZS", "VND", "VUV", "WST", "XAF", "XCD", "XOF",
-// "XPF", "YER", "ZAR", "ZMW"
+ private val stripeSupportedCurrencies = listOf("AUD", "EUR", "GBP", "USD", "INR", "PLN", "SGD", "MYR")
}
}
diff --git a/paymentsheet/src/test/resources/fpx-support.csv b/paymentsheet/src/test/resources/fpx-support.csv
new file mode 100644
index 00000000000..0f0fd8e13d4
--- /dev/null
+++ b/paymentsheet/src/test/resources/fpx-support.csv
@@ -0,0 +1,49 @@
+lpm, hasCustomer, allowsDelayedPayment, intentSetupFutureUsage, intentHasShipping, intentLpms, supportCustomerSavedCard, formExists, formType, supportsAdding
+fpx, true, true, off_session, false, card/fpx, false, false, not available, false
+fpx, true, true, off_session, false, card/eps/fpx, false, false, not available, false
+fpx, true, false, off_session, false, card/fpx, false, false, not available, false
+fpx, true, false, off_session, false, card/eps/fpx, false, false, not available, false
+fpx, true, true, on_session, false, card/fpx, false, false, not available, false
+fpx, true, true, on_session, false, card/eps/fpx, false, false, not available, false
+fpx, true, false, on_session, false, card/fpx, false, false, not available, false
+fpx, true, false, on_session, false, card/eps/fpx, false, false, not available, false
+fpx, true, true, null, false, card/fpx, false, true, oneTime, true
+fpx, true, true, null, false, card/eps/fpx, false, true, oneTime, true
+fpx, true, false, null, false, card/fpx, false, true, oneTime, true
+fpx, true, false, null, false, card/eps/fpx, false, true, oneTime, true
+fpx, false, true, off_session, false, card/fpx, false, false, not available, false
+fpx, false, true, off_session, false, card/eps/fpx, false, false, not available, false
+fpx, false, false, off_session, false, card/fpx, false, false, not available, false
+fpx, false, false, off_session, false, card/eps/fpx, false, false, not available, false
+fpx, false, true, on_session, false, card/fpx, false, false, not available, false
+fpx, false, true, on_session, false, card/eps/fpx, false, false, not available, false
+fpx, false, false, on_session, false, card/fpx, false, false, not available, false
+fpx, false, false, on_session, false, card/eps/fpx, false, false, not available, false
+fpx, false, true, null, false, card/fpx, false, true, oneTime, true
+fpx, false, true, null, false, card/eps/fpx, false, true, oneTime, true
+fpx, false, false, null, false, card/fpx, false, true, oneTime, true
+fpx, false, false, null, false, card/eps/fpx, false, true, oneTime, true
+fpx, true, true, off_session, true, card/fpx, false, false, not available, false
+fpx, true, true, off_session, true, card/eps/fpx, false, false, not available, false
+fpx, true, false, off_session, true, card/fpx, false, false, not available, false
+fpx, true, false, off_session, true, card/eps/fpx, false, false, not available, false
+fpx, true, true, on_session, true, card/fpx, false, false, not available, false
+fpx, true, true, on_session, true, card/eps/fpx, false, false, not available, false
+fpx, true, false, on_session, true, card/fpx, false, false, not available, false
+fpx, true, false, on_session, true, card/eps/fpx, false, false, not available, false
+fpx, true, true, null, true, card/fpx, false, true, oneTime, true
+fpx, true, true, null, true, card/eps/fpx, false, true, oneTime, true
+fpx, true, false, null, true, card/fpx, false, true, oneTime, true
+fpx, true, false, null, true, card/eps/fpx, false, true, oneTime, true
+fpx, false, true, off_session, true, card/fpx, false, false, not available, false
+fpx, false, true, off_session, true, card/eps/fpx, false, false, not available, false
+fpx, false, false, off_session, true, card/fpx, false, false, not available, false
+fpx, false, false, off_session, true, card/eps/fpx, false, false, not available, false
+fpx, false, true, on_session, true, card/fpx, false, false, not available, false
+fpx, false, true, on_session, true, card/eps/fpx, false, false, not available, false
+fpx, false, false, on_session, true, card/fpx, false, false, not available, false
+fpx, false, false, on_session, true, card/eps/fpx, false, false, not available, false
+fpx, false, true, null, true, card/fpx, false, true, oneTime, true
+fpx, false, true, null, true, card/eps/fpx, false, true, oneTime, true
+fpx, false, false, null, true, card/fpx, false, true, oneTime, true
+fpx, false, false, null, true, card/eps/fpx, false, true, oneTime, true
diff --git a/scripts/lokalise/lokalise_client.rb b/scripts/lokalise/lokalise_client.rb
index 7acb8c26958..772c035395f 100644
--- a/scripts/lokalise/lokalise_client.rb
+++ b/scripts/lokalise/lokalise_client.rb
@@ -31,6 +31,9 @@ def create_key(key_object)
{
"key_name": {
"android": key_object[:key_name],
+ "ios": key_object[:key_name],
+ "web": key_object[:key_name],
+ "other": key_object[:key_name],
},
"platforms": ["android"],
"filenames": {