diff --git a/paymentsheet/src/main/java/com/stripe/android/common/model/CommonConfiguration.kt b/paymentsheet/src/main/java/com/stripe/android/common/model/CommonConfiguration.kt index 8bfece87f20..8a65cc2fa40 100644 --- a/paymentsheet/src/main/java/com/stripe/android/common/model/CommonConfiguration.kt +++ b/paymentsheet/src/main/java/com/stripe/android/common/model/CommonConfiguration.kt @@ -157,3 +157,26 @@ private fun String.isEKClientSecretValid(): Boolean { } private const val EK_CLIENT_SECRET_VALID_REGEX_PATTERN = "^ek_[^_](.)+$" + +internal fun CommonConfiguration.containsVolatileDifferences( + other: CommonConfiguration +): Boolean { + return toVolatileConfiguration() != other.toVolatileConfiguration() +} + +/** + * Creates a subset of the [CommonConfiguration] values that affect the behavior of [PaymentSelection]. + */ +private fun CommonConfiguration.toVolatileConfiguration(): VolatileCommonConfiguration { + return VolatileCommonConfiguration( + defaultBillingDetails = defaultBillingDetails, + billingDetailsCollectionConfiguration = billingDetailsCollectionConfiguration, + cardBrandAcceptance = cardBrandAcceptance, + ) +} + +private data class VolatileCommonConfiguration( + val defaultBillingDetails: PaymentSheet.BillingDetails?, + val billingDetailsCollectionConfiguration: PaymentSheet.BillingDetailsCollectionConfiguration, + val cardBrandAcceptance: PaymentSheet.CardBrandAcceptance, +) diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetConfigurationKtx.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetConfigurationKtx.kt index 85e42156e53..af2b2244c7b 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetConfigurationKtx.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/PaymentSheetConfigurationKtx.kt @@ -4,20 +4,12 @@ import androidx.compose.material.darkColors import androidx.compose.material.lightColors import androidx.compose.ui.graphics.Color import androidx.compose.ui.unit.sp -import com.stripe.android.model.CardBrand -import com.stripe.android.paymentsheet.addresselement.AddressDetails import com.stripe.android.uicore.PrimaryButtonColors import com.stripe.android.uicore.PrimaryButtonShape import com.stripe.android.uicore.PrimaryButtonTypography import com.stripe.android.uicore.StripeTheme import com.stripe.android.uicore.StripeThemeDefaults -internal fun PaymentSheet.Configuration.containsVolatileDifferences( - other: PaymentSheet.Configuration -): Boolean { - return toVolatileConfiguration() != other.toVolatileConfiguration() -} - internal fun PaymentSheet.Appearance.parseAppearance() { StripeTheme.colorsLightMutable = StripeThemeDefaults.colorsLight.copy( component = Color(colorsLight.component), @@ -88,57 +80,3 @@ internal fun PaymentSheet.Appearance.parseAppearance() { ) ) } - -/** - * Creates a subset of the [PaymentSheet.Configuration] of values that affect the functional behavior of - * [PaymentSheet]. The items not included mainly affect how [PaymentSheet] will look but not affect what - * payment options are available to the customer: - * - UI elements in [PaymentSheet.GooglePayConfiguration]: - * - [PaymentSheet.GooglePayConfiguration.amount] - * - [PaymentSheet.GooglePayConfiguration.label] - * - [PaymentSheet.GooglePayConfiguration.buttonType] - * - [PaymentSheet.Configuration.merchantDisplayName] - * - [PaymentSheet.Configuration.primaryButtonColor] - * - [PaymentSheet.Configuration.appearance] - * - [PaymentSheet.Configuration.primaryButtonLabel] - */ -private fun PaymentSheet.Configuration.toVolatileConfiguration(): VolatilePaymentSheetConfiguration { - return VolatilePaymentSheetConfiguration( - customer = customer, - googlePay = googlePay?.toVolatileConfiguration(), - defaultBillingDetails = defaultBillingDetails, - shippingDetails = shippingDetails, - allowsDelayedPaymentMethods = allowsDelayedPaymentMethods, - allowsPaymentMethodsRequiringShippingAddress = allowsPaymentMethodsRequiringShippingAddress, - billingDetailsCollectionConfiguration = billingDetailsCollectionConfiguration, - preferredNetworks = preferredNetworks, - allowsRemovalOfLastSavedPaymentMethod = allowsRemovalOfLastSavedPaymentMethod, - ) -} - -private fun PaymentSheet.GooglePayConfiguration.toVolatileConfiguration(): - VolatilePaymentSheetConfiguration.GooglePayConfiguration { - return VolatilePaymentSheetConfiguration.GooglePayConfiguration( - environment = environment, - countryCode = countryCode, - currencyCode = currencyCode, - ) -} - -private data class VolatilePaymentSheetConfiguration( - val customer: PaymentSheet.CustomerConfiguration?, - val googlePay: GooglePayConfiguration?, - val defaultBillingDetails: PaymentSheet.BillingDetails?, - val shippingDetails: AddressDetails?, - val allowsDelayedPaymentMethods: Boolean, - val allowsPaymentMethodsRequiringShippingAddress: Boolean, - val billingDetailsCollectionConfiguration: PaymentSheet.BillingDetailsCollectionConfiguration, - val preferredNetworks: List, - val allowsRemovalOfLastSavedPaymentMethod: Boolean, -) { - data class GooglePayConfiguration( - val environment: PaymentSheet.GooglePayConfiguration.Environment, - val countryCode: String, - val currencyCode: String? = null, - ) -} diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/flowcontroller/PaymentSelectionUpdater.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/flowcontroller/PaymentSelectionUpdater.kt index 59d26446eca..0c0352908f4 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/flowcontroller/PaymentSelectionUpdater.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/flowcontroller/PaymentSelectionUpdater.kt @@ -1,8 +1,9 @@ package com.stripe.android.paymentsheet.flowcontroller +import com.stripe.android.common.model.asCommonConfiguration +import com.stripe.android.common.model.containsVolatileDifferences import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadata import com.stripe.android.paymentsheet.PaymentSheet -import com.stripe.android.paymentsheet.containsVolatileDifferences import com.stripe.android.paymentsheet.model.PaymentSelection import com.stripe.android.paymentsheet.state.PaymentSheetState import javax.inject.Inject @@ -26,8 +27,8 @@ internal class DefaultPaymentSelectionUpdater @Inject constructor() : PaymentSel ): PaymentSelection? { return currentSelection?.takeIf { selection -> canUseSelection(selection, newState) && previousConfig?.let { previousConfig -> - !previousConfig.containsVolatileDifferences(newConfig) - } ?: true + !previousConfig.asCommonConfiguration().containsVolatileDifferences(newConfig.asCommonConfiguration()) + } != false } ?: newState.paymentSelection } diff --git a/paymentsheet/src/test/java/com/stripe/android/common/model/CommonConfigurationFactory.kt b/paymentsheet/src/test/java/com/stripe/android/common/model/CommonConfigurationFactory.kt new file mode 100644 index 00000000000..743a7028d51 --- /dev/null +++ b/paymentsheet/src/test/java/com/stripe/android/common/model/CommonConfigurationFactory.kt @@ -0,0 +1,40 @@ +package com.stripe.android.common.model + +import com.stripe.android.ExperimentalCardBrandFilteringApi +import com.stripe.android.model.CardBrand +import com.stripe.android.paymentsheet.PaymentSheet +import com.stripe.android.paymentsheet.addresselement.AddressDetails + +internal object CommonConfigurationFactory { + @OptIn(ExperimentalCardBrandFilteringApi::class) + fun create( + merchantDisplayName: String = "Example, Inc.", + customer: PaymentSheet.CustomerConfiguration? = null, + googlePay: PaymentSheet.GooglePayConfiguration? = null, + defaultBillingDetails: PaymentSheet.BillingDetails? = null, + shippingDetails: AddressDetails? = null, + allowsDelayedPaymentMethods: Boolean = true, + allowsPaymentMethodsRequiringShippingAddress: Boolean = true, + billingDetailsCollectionConfiguration: PaymentSheet.BillingDetailsCollectionConfiguration = + PaymentSheet.BillingDetailsCollectionConfiguration(), + preferredNetworks: List = emptyList(), + allowsRemovalOfLastSavedPaymentMethod: Boolean = true, + paymentMethodOrder: List = emptyList(), + externalPaymentMethods: List = emptyList(), + cardBrandAcceptance: PaymentSheet.CardBrandAcceptance = PaymentSheet.CardBrandAcceptance.all(), + ): CommonConfiguration = CommonConfiguration( + merchantDisplayName = merchantDisplayName, + customer = customer, + googlePay = googlePay, + defaultBillingDetails = defaultBillingDetails, + shippingDetails = shippingDetails, + allowsDelayedPaymentMethods = allowsDelayedPaymentMethods, + allowsPaymentMethodsRequiringShippingAddress = allowsPaymentMethodsRequiringShippingAddress, + billingDetailsCollectionConfiguration = billingDetailsCollectionConfiguration, + preferredNetworks = preferredNetworks, + allowsRemovalOfLastSavedPaymentMethod = allowsRemovalOfLastSavedPaymentMethod, + paymentMethodOrder = paymentMethodOrder, + externalPaymentMethods = externalPaymentMethods, + cardBrandAcceptance = cardBrandAcceptance, + ) +} diff --git a/paymentsheet/src/test/java/com/stripe/android/common/model/CommonConfigurationTest.kt b/paymentsheet/src/test/java/com/stripe/android/common/model/CommonConfigurationTest.kt new file mode 100644 index 00000000000..4223f0254dd --- /dev/null +++ b/paymentsheet/src/test/java/com/stripe/android/common/model/CommonConfigurationTest.kt @@ -0,0 +1,47 @@ +package com.stripe.android.common.model + +import com.google.common.truth.Truth.assertThat +import com.stripe.android.ExperimentalCardBrandFilteringApi +import com.stripe.android.paymentsheet.PaymentSheet +import org.junit.Test + +@OptIn(ExperimentalCardBrandFilteringApi::class) +internal class CommonConfigurationTest { + private val configuration = CommonConfigurationFactory.create() + + @Test + fun `'containVolatileDifferences' should return false when no volatile differences are found`() { + val changedConfiguration = configuration.copy( + merchantDisplayName = "New merchant, Inc.", + ) + + assertThat(configuration.containsVolatileDifferences(changedConfiguration)).isFalse() + } + + @Test + fun `'containVolatileDifferences' should return true when volatile differences are found`() { + val configWithCardBrandAcceptanceChanges = configuration.copy( + cardBrandAcceptance = PaymentSheet.CardBrandAcceptance.disallowed( + listOf(PaymentSheet.CardBrandAcceptance.BrandCategory.Visa) + ) + ) + + assertThat(configuration.containsVolatileDifferences(configWithCardBrandAcceptanceChanges)).isTrue() + + val configWithBillingDetailsChanges = configuration.copy( + defaultBillingDetails = PaymentSheet.BillingDetails( + name = "Jenny Richards", + ), + ) + + assertThat(configuration.containsVolatileDifferences(configWithBillingDetailsChanges)).isTrue() + + val configWithBillingConfigChanges = configuration.copy( + billingDetailsCollectionConfiguration = PaymentSheet.BillingDetailsCollectionConfiguration( + name = PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Never, + ), + ) + + assertThat(configuration.containsVolatileDifferences(configWithBillingConfigChanges)).isTrue() + } +} diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetConfigurationKtxTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetConfigurationKtxTest.kt index 90722349406..b33c820ca39 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetConfigurationKtxTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/PaymentSheetConfigurationKtxTest.kt @@ -2,7 +2,6 @@ package com.stripe.android.paymentsheet import android.content.res.ColorStateList import android.graphics.Color -import com.google.common.truth.Truth.assertThat import com.stripe.android.common.model.CommonConfiguration import com.stripe.android.common.model.asCommonConfiguration import com.stripe.android.paymentsheet.addresselement.AddressDetails @@ -11,89 +10,6 @@ import java.lang.IllegalArgumentException import kotlin.test.assertFailsWith class PaymentSheetConfigurationKtxTest { - @Test - fun `'containVolatileDifferences' should return false when no volatile differences are found`() { - val changedConfiguration = configuration.copy( - merchantDisplayName = "New merchant, Inc.", - primaryButtonColor = ColorStateList.valueOf(Color.GREEN), - googlePay = PaymentSheet.GooglePayConfiguration( - environment = PaymentSheet.GooglePayConfiguration.Environment.Test, - countryCode = "CA", - currencyCode = "CAD", - amount = 6899, - label = "New merchant, Inc.", - buttonType = PaymentSheet.GooglePayConfiguration.ButtonType.Plain, - ), - primaryButtonLabel = "Pay", - ) - - assertThat(configuration.containsVolatileDifferences(changedConfiguration)).isFalse() - } - - @Test - fun `'containVolatileDifferences' should return true when volatile differences are found`() { - val configWithGooglePayChanges = configuration.copy( - googlePay = PaymentSheet.GooglePayConfiguration( - environment = PaymentSheet.GooglePayConfiguration.Environment.Production, - countryCode = "US", - currencyCode = "USD", - amount = 6899, - label = "New merchant, Inc.", - buttonType = PaymentSheet.GooglePayConfiguration.ButtonType.Plain, - ), - ) - - assertThat(configuration.containsVolatileDifferences(configWithGooglePayChanges)).isTrue() - - val configWithBillingDetailsChanges = configuration.copy( - defaultBillingDetails = PaymentSheet.BillingDetails( - name = "Jenny Richards", - ), - ) - - assertThat(configuration.containsVolatileDifferences(configWithBillingDetailsChanges)).isTrue() - - val configWithShippingDetailsChanges = configuration.copy( - shippingDetails = AddressDetails( - name = "Jenny Richards", - ), - ) - - assertThat(configuration.containsVolatileDifferences(configWithShippingDetailsChanges)).isTrue() - - val configWithBillingConfigChanges = configuration.copy( - billingDetailsCollectionConfiguration = PaymentSheet.BillingDetailsCollectionConfiguration( - name = PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Never, - ), - ) - - assertThat(configuration.containsVolatileDifferences(configWithBillingConfigChanges)).isTrue() - - val configWithAllowsDelayedPaymentMethodChanges = configuration.copy( - allowsDelayedPaymentMethods = true, - ) - - assertThat( - configuration.containsVolatileDifferences(configWithAllowsDelayedPaymentMethodChanges) - ).isTrue() - - val configWithAllowsPaymentMethodsRequiringShippingAddressChanges = configuration.copy( - allowsPaymentMethodsRequiringShippingAddress = true, - ) - - assertThat( - configuration.containsVolatileDifferences(configWithAllowsPaymentMethodsRequiringShippingAddressChanges) - ).isTrue() - - val configWithAllowRemovalOfLastPaymentMethodChanges = configuration.copy( - allowsRemovalOfLastSavedPaymentMethod = false, - ) - - assertThat( - configuration.containsVolatileDifferences(configWithAllowRemovalOfLastPaymentMethodChanges) - ).isTrue() - } - @Test fun `'validate' should fail when ephemeral key secret is blank`() { val configWithBlankEphemeralKeySecret = configuration.copy( diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/flowcontroller/PaymentSelectionUpdaterTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/flowcontroller/PaymentSelectionUpdaterTest.kt index 3e79139db9a..584857c6b41 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentsheet/flowcontroller/PaymentSelectionUpdaterTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentsheet/flowcontroller/PaymentSelectionUpdaterTest.kt @@ -326,10 +326,7 @@ class PaymentSelectionUpdaterTest { val existingSelection = PaymentSelection.GooglePay val newConfig = defaultPaymentSheetConfiguration.copy( - customer = PaymentSheet.CustomerConfiguration( - id = "id1", - ephemeralKeySecret = "ek_123", - ) + defaultBillingDetails = PaymentSheet.BillingDetails(email = "hi-jay@example.com") ) val newState = mockPaymentSheetStateWithPaymentIntent( config = newConfig