Skip to content

Commit

Permalink
Pass incentive information to IBP flow (#9715)
Browse files Browse the repository at this point in the history
  • Loading branch information
tillh-stripe authored Dec 3, 2024
1 parent 1667ce6 commit 14260a3
Show file tree
Hide file tree
Showing 18 changed files with 189 additions and 111 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import com.stripe.android.confirmPaymentIntent
import com.stripe.android.financialconnections.FinancialConnections
import com.stripe.android.financialconnections.FinancialConnectionsSheet
import com.stripe.android.financialconnections.FinancialConnectionsSheet.ElementsSessionContext
import com.stripe.android.financialconnections.FinancialConnectionsSheet.ElementsSessionContext.InitializationMode
import com.stripe.android.financialconnections.FinancialConnectionsSheetForTokenResult
import com.stripe.android.financialconnections.FinancialConnectionsSheetResult
import com.stripe.android.financialconnections.analytics.FinancialConnectionsEvent
Expand Down Expand Up @@ -133,7 +132,6 @@ internal class FinancialConnectionsPlaygroundViewModel(
ephemeralKey = it.ephemeralKey,
customerId = it.customerId,
elementsSessionContext = ElementsSessionContext(
initializationMode = InitializationMode.PaymentIntent(it.intentId),
amount = it.amount,
currency = it.currency,
linkMode = LinkMode.LinkPaymentMethod,
Expand All @@ -145,6 +143,7 @@ internal class FinancialConnectionsPlaygroundViewModel(
phone = null,
phoneCountryCode = null,
),
incentiveEligibilitySession = null,
),
experience = settings.get<ExperienceSetting>().selectedOption,
integrationType = settings.get<IntegrationTypeSetting>().selectedOption,
Expand Down
24 changes: 0 additions & 24 deletions financial-connections/api/financial-connections.api
Original file line number Diff line number Diff line change
Expand Up @@ -169,30 +169,6 @@ public final class com/stripe/android/financialconnections/FinancialConnectionsS
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$DeferredIntent$Creator : android/os/Parcelable$Creator {
public fun <init> ()V
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$DeferredIntent;
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
public final fun newArray (I)[Lcom/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$DeferredIntent;
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$PaymentIntent$Creator : android/os/Parcelable$Creator {
public fun <init> ()V
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$PaymentIntent;
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
public final fun newArray (I)[Lcom/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$PaymentIntent;
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$SetupIntent$Creator : android/os/Parcelable$Creator {
public fun <init> ()V
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$SetupIntent;
public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object;
public final fun newArray (I)[Lcom/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$InitializationMode$SetupIntent;
public synthetic fun newArray (I)[Ljava/lang/Object;
}

public final class com/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$PrefillDetails$Creator : android/os/Parcelable$Creator {
public fun <init> ()V
public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/financialconnections/FinancialConnectionsSheet$ElementsSessionContext$PrefillDetails;
Expand Down
1 change: 1 addition & 0 deletions financial-connections/detekt-baseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<CurrentIssues>
<ID>ConstructorParameterNaming:FinancialConnectionsAuthorizationSession.kt$FinancialConnectionsAuthorizationSession$@SerialName(value = "is_oauth") private val _isOAuth: Boolean? = false</ID>
<ID>ConstructorParameterNaming:PartnerAccountsList.kt$PartnerAccount$@SerialName(value = "allow_selection") private val _allowSelection: Boolean? = null</ID>
<ID>LargeClass:FinancialConnectionsSheetViewModelTest.kt$FinancialConnectionsSheetViewModelTest</ID>
<ID>LongMethod:AccountItem.kt$@Composable @Preview internal fun AccountItemPreview()</ID>
<ID>LongMethod:Button.kt$@Composable internal fun FinancialConnectionsButton( onClick: () -> Unit, modifier: Modifier = Modifier, type: Type = Primary, size: FinancialConnectionsButton.Size = FinancialConnectionsButton.Size.Regular, enabled: Boolean = true, loading: Boolean = false, content: @Composable (RowScope.() -> Unit) )</ID>
<ID>LongMethod:FinancialConnectionsSheetNativeActivity.kt$FinancialConnectionsSheetNativeActivity$@Composable fun NavHost( initialPane: Pane, testMode: Boolean, )</ID>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import androidx.fragment.app.Fragment
import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetForDataLauncher
import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetForTokenLauncher
import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetLauncher
import com.stripe.android.model.IncentiveEligibilitySession
import com.stripe.android.model.LinkMode
import kotlinx.parcelize.Parcelize

Expand Down Expand Up @@ -42,36 +43,14 @@ class FinancialConnectionsSheet internal constructor(
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Parcelize
data class ElementsSessionContext(
val initializationMode: InitializationMode,
val amount: Long?,
val currency: String?,
val linkMode: LinkMode?,
val billingDetails: BillingDetails?,
val prefillDetails: PrefillDetails,
val incentiveEligibilitySession: IncentiveEligibilitySession?
) : Parcelable {

val paymentIntentId: String?
get() = (initializationMode as? InitializationMode.PaymentIntent)?.paymentIntentId

val setupIntentId: String?
get() = (initializationMode as? InitializationMode.SetupIntent)?.setupIntentId

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
sealed interface InitializationMode : Parcelable {

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Parcelize
data class PaymentIntent(val paymentIntentId: String) : InitializationMode

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Parcelize
data class SetupIntent(val setupIntentId: String) : InitializationMode

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Parcelize
data object DeferredIntent : InitializationMode
}

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
@Parcelize
data class BillingDetails(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.stripe.android.financialconnections.FinancialConnectionsSheet.Element
import com.stripe.android.financialconnections.launcher.FinancialConnectionsSheetActivityArgs
import com.stripe.android.financialconnections.model.FinancialConnectionsSessionManifest
import com.stripe.android.financialconnections.utils.toApiParams
import com.stripe.android.model.IncentiveEligibilitySession
import com.stripe.android.model.LinkMode

internal object HostedAuthUrlBuilder {
Expand All @@ -20,6 +21,7 @@ internal object HostedAuthUrlBuilder {
linkMode = args.elementsSessionContext?.linkMode,
billingDetails = args.elementsSessionContext?.billingDetails,
prefillDetails = args.elementsSessionContext?.prefillDetails,
incentiveEligibilitySession = args.elementsSessionContext?.incentiveEligibilitySession,
)
}

Expand All @@ -29,6 +31,7 @@ internal object HostedAuthUrlBuilder {
linkMode: LinkMode?,
billingDetails: BillingDetails?,
prefillDetails: PrefillDetails?,
incentiveEligibilitySession: IncentiveEligibilitySession?,
): String? {
if (hostedAuthUrl == null) {
return null
Expand All @@ -40,8 +43,10 @@ internal object HostedAuthUrlBuilder {
// takes place on the web side of the flow and the payment method ID is returned to the app.
queryParams.add("return_payment_method=true")
queryParams.add("expand_payment_method=true")
queryParams.add("instantDebitsIncentive=${incentiveEligibilitySession != null}")
linkMode?.let { queryParams.add("link_mode=${it.value}") }
billingDetails?.let { queryParams.add(makeBillingDetailsQueryParams(it)) }
incentiveEligibilitySession?.let { queryParams.add("incentiveEligibilitySession=${it.id}") }
}

prefillDetails?.run {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ private class FinancialConnectionsConsumerSessionRepositoryImpl(
locale = locale,
amount = elementsSessionContext?.amount,
currency = elementsSessionContext?.currency,
paymentIntentId = null,
setupIntentId = null,
incentiveEligibilitySession = elementsSessionContext?.incentiveEligibilitySession,
requestOptions = provideApiRequestOptions(useConsumerPublishableKey = false),
requestSurface = requestSurface,
consentAction = EnteredPhoneNumberClickedSaveToLink,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import com.stripe.android.financialconnections.model.FinancialConnectionsAccount
import com.stripe.android.financialconnections.model.FinancialConnectionsSession
import com.stripe.android.financialconnections.model.FinancialConnectionsSession.StatusDetails
import com.stripe.android.financialconnections.presentation.withState
import com.stripe.android.model.IncentiveEligibilitySession
import com.stripe.android.model.LinkMode
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
Expand Down Expand Up @@ -147,7 +148,6 @@ class FinancialConnectionsSheetViewModelTest {
initialArgs = ForInstantDebits(
configuration = configuration,
elementsSessionContext = ElementsSessionContext(
initializationMode = ElementsSessionContext.InitializationMode.PaymentIntent("pi_123"),
amount = 123,
currency = "usd",
linkMode = LinkMode.LinkPaymentMethod,
Expand All @@ -156,7 +156,8 @@ class FinancialConnectionsSheetViewModelTest {
email = null,
phone = null,
phoneCountryCode = null,
)
),
incentiveEligibilitySession = null,
),
)
)
Expand All @@ -183,7 +184,6 @@ class FinancialConnectionsSheetViewModelTest {
initialArgs = ForInstantDebits(
configuration = configuration,
elementsSessionContext = ElementsSessionContext(
initializationMode = ElementsSessionContext.InitializationMode.PaymentIntent("pi_123"),
amount = 123,
currency = "usd",
linkMode = LinkMode.LinkPaymentMethod,
Expand All @@ -192,7 +192,8 @@ class FinancialConnectionsSheetViewModelTest {
email = null,
phone = null,
phoneCountryCode = null,
)
),
incentiveEligibilitySession = null,
),
)
)
Expand All @@ -218,7 +219,6 @@ class FinancialConnectionsSheetViewModelTest {
initialArgs = ForInstantDebits(
configuration = configuration,
elementsSessionContext = ElementsSessionContext(
initializationMode = ElementsSessionContext.InitializationMode.PaymentIntent("pi_123"),
amount = 123,
currency = "usd",
linkMode = null,
Expand All @@ -227,7 +227,8 @@ class FinancialConnectionsSheetViewModelTest {
email = null,
phone = null,
phoneCountryCode = null,
)
),
incentiveEligibilitySession = null,
),
)
)
Expand All @@ -240,6 +241,78 @@ class FinancialConnectionsSheetViewModelTest {
}
}

@Test
fun `init - when instant debits flow, hosted auth url contains incentive info if eligible`() = runTest {
// Given
whenever(browserManager.canOpenHttpsUrl()).thenReturn(true)
whenever(getOrFetchSync(any())).thenReturn(syncResponse)
whenever(nativeRouter.nativeAuthFlowEnabled(any())).thenReturn(false)

// When
val viewModel = createViewModel(
defaultInitialState.copy(
initialArgs = ForInstantDebits(
configuration = configuration,
elementsSessionContext = ElementsSessionContext(
amount = 123,
currency = "usd",
linkMode = null,
billingDetails = null,
prefillDetails = ElementsSessionContext.PrefillDetails(
email = null,
phone = null,
phoneCountryCode = null,
),
incentiveEligibilitySession = IncentiveEligibilitySession.PaymentIntent("pi_123"),
),
)
)
)

// Then
withState(viewModel) {
val viewEffect = it.viewEffect as OpenAuthFlowWithUrl
assertThat(viewEffect.url).contains("instantDebitsIncentive=true")
assertThat(viewEffect.url).contains("incentiveEligibilitySession=pi_123")
}
}

@Test
fun `init - when instant debits flow, hosted auth url does not contain incentive info if not eligible`() = runTest {
// Given
whenever(browserManager.canOpenHttpsUrl()).thenReturn(true)
whenever(getOrFetchSync(any())).thenReturn(syncResponse)
whenever(nativeRouter.nativeAuthFlowEnabled(any())).thenReturn(false)

// When
val viewModel = createViewModel(
defaultInitialState.copy(
initialArgs = ForInstantDebits(
configuration = configuration,
elementsSessionContext = ElementsSessionContext(
amount = 123,
currency = "usd",
linkMode = null,
billingDetails = null,
prefillDetails = ElementsSessionContext.PrefillDetails(
email = null,
phone = null,
phoneCountryCode = null,
),
incentiveEligibilitySession = null,
),
)
)
)

// Then
withState(viewModel) {
val viewEffect = it.viewEffect as OpenAuthFlowWithUrl
assertThat(viewEffect.url).contains("instantDebitsIncentive=false")
assertThat(viewEffect.url).doesNotContain("incentiveEligibilitySession")
}
}

@Test
fun `init - hosted auth url contains prefill details`() = runTest {
// Given
Expand All @@ -253,7 +326,6 @@ class FinancialConnectionsSheetViewModelTest {
initialArgs = ForInstantDebits(
configuration = configuration,
elementsSessionContext = ElementsSessionContext(
initializationMode = ElementsSessionContext.InitializationMode.PaymentIntent("pi_123"),
amount = 123,
currency = "usd",
linkMode = null,
Expand All @@ -262,7 +334,8 @@ class FinancialConnectionsSheetViewModelTest {
email = "email@email.com",
phone = "5555551234",
phoneCountryCode = "US",
)
),
incentiveEligibilitySession = null,
),
)
)
Expand Down Expand Up @@ -290,7 +363,6 @@ class FinancialConnectionsSheetViewModelTest {
initialArgs = ForInstantDebits(
configuration = configuration,
elementsSessionContext = ElementsSessionContext(
initializationMode = ElementsSessionContext.InitializationMode.PaymentIntent("pi_123"),
amount = 123,
currency = "usd",
linkMode = null,
Expand All @@ -311,7 +383,8 @@ class FinancialConnectionsSheetViewModelTest {
email = null,
phone = null,
phoneCountryCode = null,
)
),
incentiveEligibilitySession = null,
),
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ class RealCreateInstantDebitsResultTest {
billingDetails: BillingDetails? = null,
): ElementsSessionContext {
return ElementsSessionContext(
initializationMode = ElementsSessionContext.InitializationMode.PaymentIntent("pi_123"),
amount = 100L,
currency = "usd",
linkMode = linkMode,
Expand All @@ -223,7 +222,8 @@ class RealCreateInstantDebitsResultTest {
email = null,
phone = null,
phoneCountryCode = null,
)
),
incentiveEligibilitySession = null,
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import com.stripe.android.financialconnections.ApiKeyFixtures.sessionManifest
import com.stripe.android.financialconnections.ApiKeyFixtures.syncResponse
import com.stripe.android.financialconnections.CoroutineTestRule
import com.stripe.android.financialconnections.FinancialConnectionsSheet.ElementsSessionContext
import com.stripe.android.financialconnections.FinancialConnectionsSheet.ElementsSessionContext.InitializationMode
import com.stripe.android.financialconnections.TestFinancialConnectionsAnalyticsTracker
import com.stripe.android.financialconnections.analytics.FinancialConnectionsAnalyticsEvent.ConsentAgree.analyticsValue
import com.stripe.android.financialconnections.domain.GetCachedAccounts
Expand Down Expand Up @@ -122,7 +121,6 @@ class NetworkingLinkSignupViewModelTest {
val viewModel = buildViewModel(
state = NetworkingLinkSignupState(),
elementsSessionContext = ElementsSessionContext(
initializationMode = InitializationMode.PaymentIntent("pi_1234"),
amount = null,
currency = null,
linkMode = LinkMode.LinkPaymentMethod,
Expand All @@ -132,6 +130,7 @@ class NetworkingLinkSignupViewModelTest {
phone = "5555555555",
phoneCountryCode = "US",
),
incentiveEligibilitySession = null,
)
)

Expand Down
Loading

0 comments on commit 14260a3

Please sign in to comment.