Skip to content

Move CustomerState.Permissions to PaymentMethodsMetadata.CustomerMetadata #10483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
May 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
1154108
permissions in customer metadata
tianzhao-stripe Mar 20, 2025
d8827b6
migrating permissions
tianzhao-stripe Mar 20, 2025
d1d72d0
non test changes
tianzhao-stripe Mar 24, 2025
c6dcb01
tests
tianzhao-stripe Mar 24, 2025
8b8a27d
lint
tianzhao-stripe Mar 24, 2025
9b41d2b
update test to prevent unneeded get call
tianzhao-stripe Mar 24, 2025
3afedad
customerMetadataPermissions
tianzhao-stripe Mar 25, 2025
e92900c
canRemoveDuplicates default value
tianzhao-stripe Mar 25, 2025
7794196
remove comment
tianzhao-stripe Mar 25, 2025
d3fc470
constructors
tianzhao-stripe Mar 25, 2025
0ba1e3a
remove CAN_REMOVE_DUPLICATES_CUSTOMER_SHEET_VALUE
tianzhao-stripe Mar 27, 2025
dd18974
lint 2
tianzhao-stripe Mar 28, 2025
043021d
fix test after lint
tianzhao-stripe Mar 28, 2025
7b999bf
Merge branch 'master' into MOBILESDK-3324-Permissions
tianzhao-stripe Apr 4, 2025
104f648
move canRemoveDuplicate logic to customerStateHolder
tianzhao-stripe Apr 4, 2025
c6178c8
Merge branch 'master' into MOBILESDK-3324-Permissions
tianzhao-stripe Apr 25, 2025
5bf4fc3
canUpdateFullPaymentMethodDetails integration
tianzhao-stripe Apr 25, 2025
2ec479d
lint n
tianzhao-stripe Apr 26, 2025
3d5ea0d
revert changes to project xml
tianzhao-stripe Apr 26, 2025
744fdd0
revert changes to project xml 2
tianzhao-stripe Apr 26, 2025
c46824b
read from customersheet session
tianzhao-stripe Apr 26, 2025
7e3b079
Merge branch 'master' into MOBILESDK-3324-Permissions
tianzhao-stripe Apr 30, 2025
aec4c83
fix merge issues
tianzhao-stripe Apr 30, 2025
8f44ab1
pass canUpdateFullPaymentMethodDetails all the way through
tianzhao-stripe May 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions paymentsheet/api/paymentsheet.api
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,14 @@ public final class com/stripe/android/lpmfoundations/paymentmethod/CustomerMetad
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/lpmfoundations/paymentmethod/CustomerMetadata$Permissions$Creator : android/os/Parcelable$Creator {
public fun <init> ()V
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/lpmfoundations/paymentmethod/CustomerMetadata$Permissions;
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
public final fun newArray (I)[Lcom/stripe/android/lpmfoundations/paymentmethod/CustomerMetadata$Permissions;
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/lpmfoundations/paymentmethod/DisplayableCustomPaymentMethod$Creator : android/os/Parcelable$Creator {
public fun <init> ()V
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/lpmfoundations/paymentmethod/DisplayableCustomPaymentMethod;
Expand Down Expand Up @@ -2945,14 +2953,6 @@ public final class com/stripe/android/paymentsheet/state/CustomerState$DefaultPa
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/paymentsheet/state/CustomerState$Permissions$Creator : android/os/Parcelable$Creator {
public fun <init> ()V
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/paymentsheet/state/CustomerState$Permissions;
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
public final fun newArray (I)[Lcom/stripe/android/paymentsheet/state/CustomerState$Permissions;
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/paymentsheet/state/LinkState$Creator : android/os/Parcelable$Creator {
public fun <init> ()V
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/paymentsheet/state/LinkState;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import com.stripe.android.googlepaylauncher.GooglePayEnvironment
import com.stripe.android.googlepaylauncher.GooglePayRepository
import com.stripe.android.lpmfoundations.luxe.LpmRepository
import com.stripe.android.lpmfoundations.luxe.SupportedPaymentMethod
import com.stripe.android.lpmfoundations.paymentmethod.CustomerMetadata
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadata
import com.stripe.android.lpmfoundations.paymentmethod.PaymentSheetCardBrandFilter
import com.stripe.android.model.PaymentMethod
Expand Down Expand Up @@ -125,13 +126,22 @@ internal class DefaultCustomerSheetLoader(
if (isLiveModeProvider()) GooglePayEnvironment.Production else GooglePayEnvironment.Test
).isReady().first()

val customerMetadata = CustomerMetadata(
hasCustomerConfiguration = true,
isPaymentMethodSetAsDefaultEnabled = isPaymentMethodSyncDefaultEnabled,
permissions = CustomerMetadata.Permissions.createForCustomerSheet(
configuration = configuration,
customerSheetSession = customerSheetSession
)
)

return PaymentMethodMetadata.createForCustomerSheet(
elementsSession = elementsSession,
configuration = configuration,
paymentMethodSaveConsentBehavior = customerSheetSession.paymentMethodSaveConsentBehavior,
sharedDataSpecs = sharedDataSpecs,
isGooglePayReady = isGooglePayReadyAndEnabled,
isPaymentMethodSyncDefaultEnabled = isPaymentMethodSyncDefaultEnabled,
customerMetadata = customerMetadata,
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,100 @@
package com.stripe.android.lpmfoundations.paymentmethod

import android.os.Parcelable
import com.stripe.android.common.model.CommonConfiguration
import com.stripe.android.customersheet.CustomerSheet
import com.stripe.android.customersheet.data.CustomerSheetSession
import com.stripe.android.model.ElementsSession
import kotlinx.parcelize.Parcelize

@Parcelize
internal data class CustomerMetadata(
val hasCustomerConfiguration: Boolean,
val isPaymentMethodSetAsDefaultEnabled: Boolean,
) : Parcelable
val permissions: Permissions,
) : Parcelable {

@Parcelize
internal data class Permissions(
val canRemovePaymentMethods: Boolean,
val canRemoveLastPaymentMethod: Boolean,
val canRemoveDuplicates: Boolean,
val canUpdateFullPaymentMethodDetails: Boolean,
) : Parcelable {
companion object {
internal fun createForPaymentSheetCustomerSession(
configuration: CommonConfiguration,
customer: ElementsSession.Customer,
): Permissions {
val mobilePaymentElementComponent = customer.session.components.mobilePaymentElement
val canRemovePaymentMethods = when (mobilePaymentElementComponent) {
is ElementsSession.Customer.Components.MobilePaymentElement.Enabled -> {
mobilePaymentElementComponent.isPaymentMethodRemoveEnabled
}
is ElementsSession.Customer.Components.MobilePaymentElement.Disabled -> false
}

val canRemoveLastPaymentMethod = configuration.allowsRemovalOfLastSavedPaymentMethod &&
mobilePaymentElementComponent is ElementsSession.Customer.Components.MobilePaymentElement.Enabled &&
mobilePaymentElementComponent.canRemoveLastPaymentMethod

return Permissions(
canRemovePaymentMethods = canRemovePaymentMethods,
canRemoveLastPaymentMethod = canRemoveLastPaymentMethod,
// Should always remove duplicates when using `customer_session`
canRemoveDuplicates = true,
// Should always be enabled when using `customer_session`
canUpdateFullPaymentMethodDetails = true,
)
}

internal fun createForPaymentSheetLegacyEphemeralKey(
configuration: CommonConfiguration,
): Permissions {
return Permissions(
/*
* Un-scoped legacy ephemeral keys have full permissions to remove/save/modify. This should
* always be set to true.
*/
canRemovePaymentMethods = true,
/*
* Un-scoped legacy ephemeral keys normally have full permissions to remove the last payment
* method, however we do have client-side configuration option to configure this ability. This
* should eventually be removed in favor of the server-side option available with customer
* sessions.
*/
canRemoveLastPaymentMethod = configuration.allowsRemovalOfLastSavedPaymentMethod,
/*
* Removing duplicates is not applicable here since we don't filter out duplicates for for
* un-scoped ephemeral keys.
*/
canRemoveDuplicates = false,
canUpdateFullPaymentMethodDetails = false,
)
}

internal fun createForCustomerSheet(
configuration: CustomerSheet.Configuration,
customerSheetSession: CustomerSheetSession,
): Permissions {
return Permissions(
canRemovePaymentMethods = customerSheetSession.permissions.canRemovePaymentMethods,
canRemoveLastPaymentMethod = configuration.allowsRemovalOfLastSavedPaymentMethod,
canRemoveDuplicates = true,
canUpdateFullPaymentMethodDetails =
customerSheetSession.permissions.canUpdateFullPaymentMethodDetails,
)
}

// Native link uses PaymentMethodMetadata for DefaultFormHelper and doesn't use CustomerMetadata at all
internal fun createForNativeLink(): Permissions {
return Permissions(
canRemovePaymentMethods = false,
canRemoveLastPaymentMethod = false,
canRemoveDuplicates = false,
canUpdateFullPaymentMethodDetails = false
)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -277,13 +277,9 @@ internal data class PaymentMethodMetadata(
isGooglePayReady: Boolean,
linkInlineConfiguration: LinkInlineConfiguration?,
linkState: LinkState?,
customerMetadata: CustomerMetadata,
): PaymentMethodMetadata {
val linkSettings = elementsSession.linkSettings
val customerMetadata =
CustomerMetadata(
hasCustomerConfiguration = configuration.customer != null,
isPaymentMethodSetAsDefaultEnabled = getDefaultPaymentMethodsEnabled(elementsSession)
)

return PaymentMethodMetadata(
stripeIntent = elementsSession.stripeIntent,
Expand Down Expand Up @@ -322,7 +318,7 @@ internal data class PaymentMethodMetadata(
paymentMethodSaveConsentBehavior: PaymentMethodSaveConsentBehavior,
sharedDataSpecs: List<SharedDataSpec>,
isGooglePayReady: Boolean,
isPaymentMethodSyncDefaultEnabled: Boolean,
customerMetadata: CustomerMetadata,
): PaymentMethodMetadata {
return PaymentMethodMetadata(
stripeIntent = elementsSession.stripeIntent,
Expand All @@ -337,10 +333,7 @@ internal data class PaymentMethodMetadata(
merchantName = configuration.merchantDisplayName,
defaultBillingDetails = configuration.defaultBillingDetails,
shippingDetails = null,
customerMetadata = CustomerMetadata(
hasCustomerConfiguration = true,
isPaymentMethodSetAsDefaultEnabled = isPaymentMethodSyncDefaultEnabled,
),
customerMetadata = customerMetadata,
sharedDataSpecs = sharedDataSpecs,
isGooglePayReady = isGooglePayReady,
linkInlineConfiguration = null,
Expand Down Expand Up @@ -378,6 +371,7 @@ internal data class PaymentMethodMetadata(
customerMetadata = CustomerMetadata(
hasCustomerConfiguration = true,
isPaymentMethodSetAsDefaultEnabled = false,
permissions = CustomerMetadata.Permissions.createForNativeLink(),
),
sharedDataSpecs = emptyList(),
externalPaymentMethodSpecs = emptyList(),
Expand All @@ -394,12 +388,5 @@ internal data class PaymentMethodMetadata(
financialConnectionsAvailability = GetFinancialConnectionsAvailability(elementsSession = null)
)
}

private fun getDefaultPaymentMethodsEnabled(elementsSession: ElementsSession): Boolean {
val mobilePaymentElement = elementsSession.customer?.session?.components?.mobilePaymentElement
as? ElementsSession.Customer.Components.MobilePaymentElement.Enabled
return mobilePaymentElement?.isPaymentMethodSetAsDefaultEnabled
?: false
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.stripe.android.core.injection.UIContext
import com.stripe.android.core.networking.AnalyticsRequestFactory
import com.stripe.android.core.utils.DefaultDurationProvider
import com.stripe.android.core.utils.DurationProvider
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadata
import com.stripe.android.networking.PaymentAnalyticsRequestFactory
import com.stripe.android.paymentelement.AnalyticEventCallback
import com.stripe.android.paymentelement.ExperimentalAnalyticEventCallbackApi
Expand All @@ -28,10 +29,12 @@ import com.stripe.android.paymentsheet.analytics.DefaultEventReporter
import com.stripe.android.paymentsheet.analytics.EventReporter
import com.stripe.android.paymentsheet.repositories.CustomerApiRepository
import com.stripe.android.paymentsheet.repositories.CustomerRepository
import com.stripe.android.uicore.utils.mapAsStateFlow
import dagger.Binds
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Named
import javax.inject.Provider
import javax.inject.Singleton
Expand Down Expand Up @@ -119,8 +122,16 @@ internal interface EmbeddedCommonModule {
fun provideCustomerStateHolder(
savedStateHandle: SavedStateHandle,
selectionHolder: EmbeddedSelectionHolder,
paymentMethodMetadataFlow: StateFlow<PaymentMethodMetadata?>
): CustomerStateHolder {
return CustomerStateHolder(savedStateHandle, selectionHolder.selection)
val customerMetadataPermissions = paymentMethodMetadataFlow.mapAsStateFlow {
it?.customerMetadata?.permissions
}
return CustomerStateHolder(
savedStateHandle = savedStateHandle,
selection = selectionHolder.selection,
customerMetadataPermissions = customerMetadataPermissions
)
}

@Provides
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.stripe.android.core.utils.RealUserFacingLogger
import com.stripe.android.core.utils.UserFacingLogger
import com.stripe.android.googlepaylauncher.injection.GooglePayLauncherModule
import com.stripe.android.link.account.LinkAccountHolder
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadata
import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi
import com.stripe.android.paymentelement.callbacks.PaymentElementCallbackIdentifier
import com.stripe.android.paymentelement.confirmation.ConfirmationHandler
Expand All @@ -35,13 +36,16 @@ import com.stripe.android.paymentsheet.state.PaymentElementLoader
import com.stripe.android.paymentsheet.state.RetrieveCustomerEmail
import com.stripe.android.ui.core.di.CardScanModule
import com.stripe.android.uicore.image.StripeImageLoader
import com.stripe.android.uicore.utils.mapAsStateFlow
import dagger.Binds
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.plus
import javax.inject.Named
import javax.inject.Singleton
import kotlin.coroutines.CoroutineContext
Expand Down Expand Up @@ -189,6 +193,15 @@ internal interface EmbeddedPaymentElementViewModelModule {
return confirmationHandlerFactory.create(coroutineScope)
}

@Provides
fun providePaymentMethodMetadata(
confirmationStateHolder: EmbeddedConfirmationStateHolder
): StateFlow<PaymentMethodMetadata?> {
return confirmationStateHolder.stateFlow.mapAsStateFlow {
it?.paymentMethodMetadata
}
}

@Provides
fun providesConfirmationStateSupplier(
confirmationStateHolder: EmbeddedConfirmationStateHolder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal class DefaultEmbeddedUpdateScreenInteractorFactory @Inject constructor(
return DefaultUpdatePaymentMethodInteractor(
isLiveMode = paymentMethodMetadata.stripeIntent.isLiveMode,
canRemove = customerStateHolder.canRemove.value,
canUpdateFullPaymentMethodDetails = customerStateHolder.canUpdateFullPaymentMethodDetails,
canUpdateFullPaymentMethodDetails = customerStateHolder.canUpdateFullPaymentMethodDetails.value,
displayableSavedPaymentMethod = displayableSavedPaymentMethod,
cardBrandFilter = paymentMethodMetadata.cardBrandFilter,
addressCollectionMode = paymentMethodMetadata.billingDetailsCollectionConfiguration.address,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import com.stripe.android.paymentsheet.CustomerStateHolder
import com.stripe.android.paymentsheet.SavedPaymentMethodMutator
import com.stripe.android.paymentsheet.analytics.EventReporter
import com.stripe.android.ui.core.di.CardScanModule
import com.stripe.android.uicore.utils.stateFlowOf
import dagger.Binds
import dagger.BindsInstance
import dagger.Component
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.StateFlow
import javax.inject.Singleton

@Component(
Expand Down Expand Up @@ -86,6 +88,15 @@ internal interface ManageModule {
return factory.createSavedPaymentMethodMutator()
}

@Provides
fun providePaymentMethodMetadata(
paymentMethodMetadata: PaymentMethodMetadata
): StateFlow<PaymentMethodMetadata> {
return stateFlowOf(
paymentMethodMetadata
)
}

@Provides
@Singleton
@ViewModelScope
Expand Down
Loading
Loading