diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt index 1fde5080edd..f9201c22bf4 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/FinancialConnectionsSheetViewModel.kt @@ -461,7 +461,9 @@ internal class FinancialConnectionsSheetViewModel @Inject constructor( instantDebits = InstantDebitsResult( encodedPaymentMethod = paymentMethod, last4 = url.getQueryParameter(QUERY_PARAM_LAST4), - bankName = url.getQueryParameter(QUERY_BANK_NAME) + bankName = url.getQueryParameter(QUERY_BANK_NAME), + // TODO(tillh-stripe): Pull this from the URL + eligibleForIncentive = false, ), financialConnectionsSession = null, token = null diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/CreateInstantDebitsResult.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/CreateInstantDebitsResult.kt index 887ee336bf2..53900750d6d 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/CreateInstantDebitsResult.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/domain/CreateInstantDebitsResult.kt @@ -58,10 +58,26 @@ internal class RealCreateInstantDebitsResult @Inject constructor( ) } + val incentiveEligibilitySessionId = elementsSessionContext?.incentiveEligibilitySession?.id + + val eligibleForIncentive = if (incentiveEligibilitySessionId != null) { + val availableIncentives = runCatching { + consumerRepository.updateAvailableIncentives( + sessionId = incentiveEligibilitySessionId, + consumerSessionClientSecret = clientSecret, + ) + }.getOrNull() + + availableIncentives?.data?.isNotEmpty() == true + } else { + false + } + return InstantDebitsResult( encodedPaymentMethod = paymentMethod, bankName = paymentDetails.bankName, last4 = paymentDetails.last4, + eligibleForIncentive = eligibleForIncentive, ) } } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetActivityResult.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetActivityResult.kt index f604d0c9088..8447f33bf61 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetActivityResult.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetActivityResult.kt @@ -56,5 +56,6 @@ internal sealed class FinancialConnectionsSheetActivityResult : Parcelable { internal data class InstantDebitsResult( val encodedPaymentMethod: String, val last4: String?, - val bankName: String? + val bankName: String?, + val eligibleForIncentive: Boolean, ) : Parcelable diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetForInstantDebitsContract.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetForInstantDebitsContract.kt index 1c01cd40236..4ba4807f79e 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetForInstantDebitsContract.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetForInstantDebitsContract.kt @@ -45,6 +45,7 @@ class FinancialConnectionsSheetForInstantDebitsContract : encodedPaymentMethod = instantDebits.encodedPaymentMethod, last4 = instantDebits.last4, bankName = instantDebits.bankName, + eligibleForIncentive = instantDebits.eligibleForIncentive, ) } } diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetInstantDebitsResult.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetInstantDebitsResult.kt index f7ff5b45e16..178ab2266e9 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetInstantDebitsResult.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetInstantDebitsResult.kt @@ -11,16 +11,14 @@ import kotlinx.parcelize.Parcelize sealed class FinancialConnectionsSheetInstantDebitsResult : Parcelable { /** * The customer completed the connections session. - * @param paymentMethodId The payment method id, that can be used to confirm the payment. - * @param last4 The last 4 digits of the bank account. - * @param bankName The name of the bank. */ @Parcelize @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) data class Completed( val encodedPaymentMethod: String, val last4: String?, - val bankName: String? + val bankName: String?, + val eligibleForIncentive: Boolean, ) : FinancialConnectionsSheetInstantDebitsResult() /** diff --git a/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/FinancialConnectionsConsumerSessionRepository.kt b/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/FinancialConnectionsConsumerSessionRepository.kt index 80378469a0e..53f2ec7d591 100644 --- a/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/FinancialConnectionsConsumerSessionRepository.kt +++ b/financial-connections/src/main/java/com/stripe/android/financialconnections/repository/FinancialConnectionsConsumerSessionRepository.kt @@ -17,6 +17,7 @@ import com.stripe.android.model.ConsumerSessionSignup import com.stripe.android.model.ConsumerSignUpConsentAction.EnteredPhoneNumberClickedSaveToLink import com.stripe.android.model.CustomEmailType import com.stripe.android.model.SharePaymentDetails +import com.stripe.android.model.UpdateAvailableIncentives import com.stripe.android.model.VerificationType import com.stripe.android.repository.ConsumersApiService import kotlinx.coroutines.sync.Mutex @@ -69,6 +70,11 @@ internal interface FinancialConnectionsConsumerSessionRepository { billingPhone: String?, ): SharePaymentDetails + suspend fun updateAvailableIncentives( + sessionId: String, + consumerSessionClientSecret: String, + ): UpdateAvailableIncentives + companion object { operator fun invoke( consumersApiService: ConsumersApiService, @@ -238,6 +244,18 @@ private class FinancialConnectionsConsumerSessionRepositoryImpl( ).getOrThrow() } + override suspend fun updateAvailableIncentives( + sessionId: String, + consumerSessionClientSecret: String, + ): UpdateAvailableIncentives { + return consumersApiService.updateAvailableIncentives( + sessionId = sessionId, + consumerSessionClientSecret = consumerSessionClientSecret, + requestSurface = requestSurface, + requestOptions = provideApiRequestOptions(useConsumerPublishableKey = true), + ).getOrThrow() + } + private suspend fun postConsumerSession( email: String, clientSecret: String @@ -266,6 +284,9 @@ private class FinancialConnectionsConsumerSessionRepositoryImpl( signup: ConsumerSessionSignup, ) { logger.debug("SYNC_CACHE: updating local consumer session from signUp") - consumerSessionRepository.storeNewConsumerSession(signup.consumerSession, signup.publishableKey) + consumerSessionRepository.storeNewConsumerSession( + consumerSession = signup.consumerSession, + publishableKey = signup.publishableKey, + ) } } diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/domain/RealCreateInstantDebitsResultTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/domain/RealCreateInstantDebitsResultTest.kt index 57852fabf23..c7564be2517 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/domain/RealCreateInstantDebitsResultTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/domain/RealCreateInstantDebitsResultTest.kt @@ -1,21 +1,28 @@ package com.stripe.android.financialconnections.domain +import com.google.common.truth.Truth.assertThat import com.stripe.android.financialconnections.FinancialConnectionsSheet.ElementsSessionContext import com.stripe.android.financialconnections.FinancialConnectionsSheet.ElementsSessionContext.BillingDetails import com.stripe.android.financialconnections.repository.CachedConsumerSession import com.stripe.android.financialconnections.repository.FinancialConnectionsConsumerSessionRepository import com.stripe.android.financialconnections.repository.FinancialConnectionsRepository import com.stripe.android.model.ConsumerPaymentDetails +import com.stripe.android.model.IncentiveEligibilitySession +import com.stripe.android.model.LinkConsumerIncentive import com.stripe.android.model.LinkMode import com.stripe.android.model.SharePaymentDetails +import com.stripe.android.model.UpdateAvailableIncentives import kotlinx.coroutines.test.runTest import org.junit.Test import org.mockito.kotlin.any import org.mockito.kotlin.anyOrNull import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq import org.mockito.kotlin.mock +import org.mockito.kotlin.never import org.mockito.kotlin.verify import org.mockito.kotlin.verifyNoInteractions +import org.mockito.kotlin.whenever class RealCreateInstantDebitsResultTest { @@ -167,6 +174,69 @@ class RealCreateInstantDebitsResultTest { ) } + @Test + fun `Skips checking available incentives if not incentive eligible`() = runTest { + val consumerRepository = makeConsumerSessionRepository() + val repository = makeRepository() + + val createInstantDebitResult = RealCreateInstantDebitsResult( + consumerRepository = consumerRepository, + repository = repository, + consumerSessionProvider = { makeCachedConsumerSession() }, + elementsSessionContext = makeElementsSessionContext( + linkMode = LinkMode.LinkPaymentMethod, + incentiveEligibilitySession = null, + ), + ) + + val result = createInstantDebitResult("bank_account_id_001") + + verify(consumerRepository, never()).updateAvailableIncentives( + sessionId = any(), + consumerSessionClientSecret = any(), + ) + + assertThat(result.eligibleForIncentive).isFalse() + } + + @Test + fun `Checks available incentives if eligible`() = runTest { + val consumerRepository = makeConsumerSessionRepository() + val repository = makeRepository() + val consumerSession = makeCachedConsumerSession() + + val createInstantDebitResult = RealCreateInstantDebitsResult( + consumerRepository = consumerRepository, + repository = repository, + consumerSessionProvider = { consumerSession }, + elementsSessionContext = makeElementsSessionContext( + linkMode = LinkMode.LinkPaymentMethod, + incentiveEligibilitySession = IncentiveEligibilitySession.PaymentIntent("pi_123"), + ), + ) + + whenever( + consumerRepository.updateAvailableIncentives( + sessionId = eq("pi_123"), + consumerSessionClientSecret = eq("clientSecret"), + ) + ).thenReturn( + UpdateAvailableIncentives( + data = listOf( + LinkConsumerIncentive( + incentiveParams = LinkConsumerIncentive.IncentiveParams( + paymentMethod = "link_instant_debits", + ), + incentiveDisplayText = "$5", + ) + ) + ) + ) + + val result = createInstantDebitResult("bank_account_id_001") + assertThat(result.eligibleForIncentive).isTrue() + } + private fun makeConsumerSessionRepository(): FinancialConnectionsConsumerSessionRepository { val consumerPaymentDetails = ConsumerPaymentDetails( paymentDetails = listOf( @@ -212,6 +282,7 @@ class RealCreateInstantDebitsResultTest { private fun makeElementsSessionContext( linkMode: LinkMode?, billingDetails: BillingDetails? = null, + incentiveEligibilitySession: IncentiveEligibilitySession? = null, ): ElementsSessionContext { return ElementsSessionContext( amount = 100L, @@ -223,7 +294,7 @@ class RealCreateInstantDebitsResultTest { phone = null, phoneCountryCode = null, ), - incentiveEligibilitySession = null, + incentiveEligibilitySession = incentiveEligibilitySession, ) } } diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetForInstantDebitsLauncherTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetForInstantDebitsLauncherTest.kt index 5ffabc08c91..f95f82babef 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetForInstantDebitsLauncherTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/launcher/FinancialConnectionsSheetForInstantDebitsLauncherTest.kt @@ -23,6 +23,7 @@ class FinancialConnectionsSheetForInstantDebitsLauncherTest { encodedPaymentMethod = encodedPaymentMethod, last4 = "1234", bankName = "Bank of America", + eligibleForIncentive = false, ) ) @@ -46,6 +47,7 @@ class FinancialConnectionsSheetForInstantDebitsLauncherTest { encodedPaymentMethod = encodedPaymentMethod, last4 = "1234", bankName = "Bank of America", + eligibleForIncentive = false, ) ) } diff --git a/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModelTest.kt b/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModelTest.kt index 2d5cc79b11f..2539ef333dd 100644 --- a/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModelTest.kt +++ b/financial-connections/src/test/java/com/stripe/android/financialconnections/presentation/FinancialConnectionsSheetNativeViewModelTest.kt @@ -327,6 +327,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { encodedPaymentMethod = encodedPaymentMethod, last4 = "4242", bankName = "Stripe Bank", + eligibleForIncentive = false, ) }, ) @@ -339,6 +340,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { encodedPaymentMethod = encodedPaymentMethod, last4 = "4242", bankName = "Stripe Bank", + eligibleForIncentive = false, ), ) ) @@ -382,6 +384,7 @@ internal class FinancialConnectionsSheetNativeViewModelTest { encodedPaymentMethod = encodedPaymentMethod, last4 = "4242", bankName = "Stripe Bank", + eligibleForIncentive = false, ) }, ) diff --git a/payments-core/src/main/java/com/stripe/android/payments/bankaccount/navigation/CollectBankAccountForInstantDebitsResult.kt b/payments-core/src/main/java/com/stripe/android/payments/bankaccount/navigation/CollectBankAccountForInstantDebitsResult.kt index 2136abd6d46..35624a531ff 100644 --- a/payments-core/src/main/java/com/stripe/android/payments/bankaccount/navigation/CollectBankAccountForInstantDebitsResult.kt +++ b/payments-core/src/main/java/com/stripe/android/payments/bankaccount/navigation/CollectBankAccountForInstantDebitsResult.kt @@ -18,7 +18,8 @@ sealed interface CollectBankAccountForInstantDebitsResult : Parcelable { val intent: StripeIntent?, val paymentMethod: PaymentMethod, val last4: String?, - val bankName: String? + val bankName: String?, + val eligibleForIncentive: Boolean, ) : CollectBankAccountForInstantDebitsResult @Parcelize @@ -51,7 +52,8 @@ internal fun CollectBankAccountResultInternal.toInstantDebitsResult(): CollectBa intent = response.intent, paymentMethod = response.instantDebitsData.paymentMethod, last4 = response.instantDebitsData.last4, - bankName = response.instantDebitsData.bankName + bankName = response.instantDebitsData.bankName, + eligibleForIncentive = response.instantDebitsData.eligibleForIncentive, ) } } diff --git a/payments-core/src/main/java/com/stripe/android/payments/bankaccount/navigation/CollectBankAccountResultInternal.kt b/payments-core/src/main/java/com/stripe/android/payments/bankaccount/navigation/CollectBankAccountResultInternal.kt index 714b5eedb82..74f9645a0a8 100644 --- a/payments-core/src/main/java/com/stripe/android/payments/bankaccount/navigation/CollectBankAccountResultInternal.kt +++ b/payments-core/src/main/java/com/stripe/android/payments/bankaccount/navigation/CollectBankAccountResultInternal.kt @@ -54,6 +54,7 @@ data class CollectBankAccountResponseInternal( data class InstantDebitsData( val paymentMethod: PaymentMethod, val last4: String?, - val bankName: String? + val bankName: String?, + val eligibleForIncentive: Boolean, ) : StripeModel } diff --git a/payments-core/src/main/java/com/stripe/android/payments/bankaccount/ui/CollectBankAccountViewModel.kt b/payments-core/src/main/java/com/stripe/android/payments/bankaccount/ui/CollectBankAccountViewModel.kt index 017c5c6b9a1..ecdafa96f6b 100644 --- a/payments-core/src/main/java/com/stripe/android/payments/bankaccount/ui/CollectBankAccountViewModel.kt +++ b/payments-core/src/main/java/com/stripe/android/payments/bankaccount/ui/CollectBankAccountViewModel.kt @@ -200,6 +200,7 @@ internal class CollectBankAccountViewModel @Inject constructor( paymentMethod = it, last4 = result.last4, bankName = result.bankName, + eligibleForIncentive = result.eligibleForIncentive, ) }, ) diff --git a/payments-model/api/payments-model.api b/payments-model/api/payments-model.api index e9282d4c658..97f637ba4ba 100644 --- a/payments-model/api/payments-model.api +++ b/payments-model/api/payments-model.api @@ -503,6 +503,14 @@ public final class com/stripe/android/model/TokenizationMethod : java/lang/Enum public static fun values ()[Lcom/stripe/android/model/TokenizationMethod; } +public final class com/stripe/android/model/UpdateAvailableIncentives$Creator : android/os/Parcelable$Creator { + public fun ()V + public final fun createFromParcel (Landroid/os/Parcel;)Lcom/stripe/android/model/UpdateAvailableIncentives; + public synthetic fun createFromParcel (Landroid/os/Parcel;)Ljava/lang/Object; + public final fun newArray (I)[Lcom/stripe/android/model/UpdateAvailableIncentives; + public synthetic fun newArray (I)[Ljava/lang/Object; +} + public final class com/stripe/payments/model/BuildConfig { public static final field BUILD_TYPE Ljava/lang/String; public static final field DEBUG Z diff --git a/payments-model/src/main/java/com/stripe/android/model/UpdateAvailableIncentives.kt b/payments-model/src/main/java/com/stripe/android/model/UpdateAvailableIncentives.kt new file mode 100644 index 00000000000..c113e40727b --- /dev/null +++ b/payments-model/src/main/java/com/stripe/android/model/UpdateAvailableIncentives.kt @@ -0,0 +1,11 @@ +package com.stripe.android.model + +import androidx.annotation.RestrictTo +import com.stripe.android.core.model.StripeModel +import kotlinx.parcelize.Parcelize + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +@Parcelize +data class UpdateAvailableIncentives( + val data: List, +) : StripeModel diff --git a/payments-model/src/main/java/com/stripe/android/model/parsers/UpdateAvailableIncentivesJsonParser.kt b/payments-model/src/main/java/com/stripe/android/model/parsers/UpdateAvailableIncentivesJsonParser.kt new file mode 100644 index 00000000000..0b060f48013 --- /dev/null +++ b/payments-model/src/main/java/com/stripe/android/model/parsers/UpdateAvailableIncentivesJsonParser.kt @@ -0,0 +1,22 @@ +package com.stripe.android.model.parsers + +import androidx.annotation.RestrictTo +import com.stripe.android.core.model.parsers.ModelJsonParser +import com.stripe.android.model.UpdateAvailableIncentives +import org.json.JSONObject + +@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) +object UpdateAvailableIncentivesJsonParser : ModelJsonParser { + + override fun parse(json: JSONObject): UpdateAvailableIncentives? { + val incentives = json.optJSONArray("data")?.let { data -> + List(data.length()) { index -> + LinkConsumerIncentiveJsonParser.parse(data.getJSONObject(index)) + } + } + + return incentives?.let { + UpdateAvailableIncentives(data = it.filterNotNull()) + } + } +} diff --git a/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt b/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt index 343faa09b4e..1daa58e62cf 100644 --- a/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt +++ b/payments-model/src/main/java/com/stripe/android/repository/ConsumersApiService.kt @@ -18,6 +18,7 @@ import com.stripe.android.model.ConsumerSignUpConsentAction import com.stripe.android.model.CustomEmailType import com.stripe.android.model.IncentiveEligibilitySession import com.stripe.android.model.SharePaymentDetails +import com.stripe.android.model.UpdateAvailableIncentives import com.stripe.android.model.VerificationType import com.stripe.android.model.parsers.AttachConsumerToLinkAccountSessionJsonParser import com.stripe.android.model.parsers.ConsumerPaymentDetailsJsonParser @@ -25,6 +26,7 @@ import com.stripe.android.model.parsers.ConsumerSessionJsonParser import com.stripe.android.model.parsers.ConsumerSessionLookupJsonParser import com.stripe.android.model.parsers.ConsumerSessionSignupJsonParser import com.stripe.android.model.parsers.SharePaymentDetailsJsonParser +import com.stripe.android.model.parsers.UpdateAvailableIncentivesJsonParser import java.util.Locale @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @@ -91,6 +93,13 @@ interface ConsumersApiService { requestOptions: ApiRequest.Options, extraParams: Map, ): Result + + suspend fun updateAvailableIncentives( + sessionId: String, + consumerSessionClientSecret: String, + requestSurface: String, + requestOptions: ApiRequest.Options, + ): Result } @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) @@ -314,6 +323,30 @@ class ConsumersApiServiceImpl( ) } + override suspend fun updateAvailableIncentives( + sessionId: String, + consumerSessionClientSecret: String, + requestSurface: String, + requestOptions: ApiRequest.Options, + ): Result { + return executeRequestWithResultParser( + stripeErrorJsonParser = stripeErrorJsonParser, + stripeNetworkClient = stripeNetworkClient, + request = apiRequestFactory.createPost( + url = updateAvailableIncentivesUrl, + options = requestOptions, + params = mapOf( + "request_surface" to requestSurface, + "session_id" to sessionId, + "credentials" to mapOf( + "consumer_session_client_secret" to consumerSessionClientSecret + ), + ), + ), + responseJsonParser = UpdateAvailableIncentivesJsonParser, + ) + } + internal companion object { /** @@ -356,6 +389,11 @@ class ConsumersApiServiceImpl( */ private val sharePaymentDetails: String = getApiUrl("consumers/payment_details/share") + /** + * @return `https://api.stripe.com/v1/consumers/incentives/update_available` + */ + private val updateAvailableIncentivesUrl: String = getApiUrl("consumers/incentives/update_available") + private fun getApiUrl(path: String): String { return "${ApiRequest.API_HOST}/v1/$path" } diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/paymentdatacollection/ach/USBankAccountFormViewModel.kt b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/paymentdatacollection/ach/USBankAccountFormViewModel.kt index ac00609691b..a292e6e9b27 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentsheet/paymentdatacollection/ach/USBankAccountFormViewModel.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentsheet/paymentdatacollection/ach/USBankAccountFormViewModel.kt @@ -354,6 +354,7 @@ internal class USBankAccountFormViewModel @Inject internal constructor( financialConnectionsSessionId = null, mandateText = buildMandateText(isVerifyWithMicrodeposits = false), isVerifyingWithMicrodeposits = false, + eligibleForIncentive = result.eligibleForIncentive, ) ) }