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": {