Skip to content

Commit

Permalink
Add synthetic payment method for LinkCardBrand
Browse files Browse the repository at this point in the history
  • Loading branch information
tillh-stripe committed Sep 16, 2024
1 parent 84ce028 commit 2a31812
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stripe.android.lpmfoundations.paymentmethod

import com.stripe.android.model.LinkMode
import com.stripe.android.model.PaymentIntent
import com.stripe.android.model.PaymentMethod.Type.USBankAccount

Expand Down Expand Up @@ -59,13 +60,25 @@ internal enum class AddPaymentMethodRequirement {
/** Requires that Instant Debits are possible for this transaction. */
InstantDebits {
override fun isMetBy(metadata: PaymentMethodMetadata): Boolean {
val paymentMethodTypes = metadata.stripeIntent.paymentMethodTypes
val noUsBankAccount = USBankAccount.code !in paymentMethodTypes
val supportsBankAccounts = "bank_account" in metadata.stripeIntent.linkFundingSources
val isDeferred = metadata.stripeIntent.clientSecret == null
return noUsBankAccount && supportsBankAccounts && !isDeferred
return metadata.linkMode != LinkMode.LinkCardBrand && metadata.supportsMobileInstantDebitsFlow
}
},

/** Requires that LinkCardBrand is possible for this transaction. */
LinkCardBrand {
override fun isMetBy(metadata: PaymentMethodMetadata): Boolean {
return metadata.linkMode == LinkMode.LinkCardBrand && metadata.supportsMobileInstantDebitsFlow
}
};

abstract fun isMetBy(metadata: PaymentMethodMetadata): Boolean
}

private val PaymentMethodMetadata.supportsMobileInstantDebitsFlow: Boolean
get() {
val paymentMethodTypes = stripeIntent.paymentMethodTypes
val noUsBankAccount = USBankAccount.code !in paymentMethodTypes
val supportsBankAccounts = "bank_account" in stripeIntent.linkFundingSources
val isDeferred = stripeIntent.clientSecret == null
return noUsBankAccount && supportsBankAccounts && !isDeferred
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ internal interface PaymentMethodDefinition {
fun uiDefinitionFactory(): UiDefinitionFactory
}

internal fun PaymentMethodDefinition.isSupported(metadata: PaymentMethodMetadata): Boolean {
if (type.code !in metadata.stripeIntent.paymentMethodTypes) {
internal fun PaymentMethodDefinition.isSupported(
metadata: PaymentMethodMetadata,
requireToBeIncludedInIntentPaymentMethodTypes: Boolean = true,
): Boolean {
if (requireToBeIncludedInIntentPaymentMethodTypes && type.code !in metadata.stripeIntent.paymentMethodTypes) {
return false
}
return requirementsToBeUsedAsNewPaymentMethod(metadata.hasIntentToSetup()).all { requirement ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import com.stripe.android.customersheet.ExperimentalCustomerSheetApi
import com.stripe.android.lpmfoundations.FormHeaderInformation
import com.stripe.android.lpmfoundations.luxe.SupportedPaymentMethod
import com.stripe.android.lpmfoundations.paymentmethod.definitions.ExternalPaymentMethodUiDefinitionFactory
import com.stripe.android.lpmfoundations.paymentmethod.definitions.LinkCardBrandDefinition
import com.stripe.android.lpmfoundations.paymentmethod.link.LinkInlineConfiguration
import com.stripe.android.model.ElementsSession
import com.stripe.android.model.LinkMode
import com.stripe.android.model.PaymentIntent
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.SetupIntent
Expand Down Expand Up @@ -45,6 +47,7 @@ internal data class PaymentMethodMetadata(
val isGooglePayReady: Boolean,
val linkInlineConfiguration: LinkInlineConfiguration?,
val paymentMethodSaveConsentBehavior: PaymentMethodSaveConsentBehavior,
val linkMode: LinkMode?,
val financialConnectionsAvailable: Boolean = DefaultIsFinancialConnectionsAvailable(),
) : Parcelable {
fun hasIntentToSetup(): Boolean {
Expand Down Expand Up @@ -134,16 +137,31 @@ internal data class PaymentMethodMetadata(
}

private fun supportedPaymentMethodDefinitions(): List<PaymentMethodDefinition> {
return stripeIntent.paymentMethodTypes.mapNotNull {
PaymentMethodRegistry.definitionsByCode[it]
}.filter {
it.isSupported(this)
}.filterNot {
stripeIntent.isLiveMode &&
stripeIntent.unactivatedPaymentMethods.contains(it.type.code)
}.filter { paymentMethodDefinition ->
paymentMethodDefinition.uiDefinitionFactory().canBeDisplayedInUi(paymentMethodDefinition, sharedDataSpecs)
return stripeIntent.paymentMethodTypes
.mapNotNull { PaymentMethodRegistry.definitionsByCode[it] }
.filter { it.isSupported(this) }
.withLinkCardBrandIfSupported()
.filterNot {
stripeIntent.isLiveMode &&
stripeIntent.unactivatedPaymentMethods.contains(it.type.code)
}
.filter { paymentMethodDefinition ->
paymentMethodDefinition.uiDefinitionFactory()
.canBeDisplayedInUi(paymentMethodDefinition, sharedDataSpecs)
}
}

private fun List<PaymentMethodDefinition>.withLinkCardBrandIfSupported(): List<PaymentMethodDefinition> {
if (linkMode == LinkMode.LinkCardBrand) {
val isSupported = LinkCardBrandDefinition.isSupported(
metadata = this@PaymentMethodMetadata,
requireToBeIncludedInIntentPaymentMethodTypes = false,
)
if (isSupported) {
return this + LinkCardBrandDefinition
}
}
return this
}

fun amount(): Amount? {
Expand Down Expand Up @@ -272,6 +290,7 @@ internal data class PaymentMethodMetadata(
externalPaymentMethodSpecs = externalPaymentMethodSpecs,
paymentMethodSaveConsentBehavior = elementsSession.toPaymentSheetSaveConsentBehavior(),
linkInlineConfiguration = linkInlineConfiguration,
linkMode = elementsSession.linkSettings?.linkMode,
isGooglePayReady = isGooglePayReady,
)
}
Expand Down Expand Up @@ -303,6 +322,7 @@ internal data class PaymentMethodMetadata(
linkInlineConfiguration = null,
financialConnectionsAvailable = isFinancialConnectionsAvailable(),
paymentMethodSaveConsentBehavior = PaymentMethodSaveConsentBehavior.Legacy,
linkMode = elementsSession.linkSettings?.linkMode,
externalPaymentMethodSpecs = emptyList(),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.stripe.android.lpmfoundations.paymentmethod.definitions.IdealDefiniti
import com.stripe.android.lpmfoundations.paymentmethod.definitions.InstantDebitsDefinition
import com.stripe.android.lpmfoundations.paymentmethod.definitions.KlarnaDefinition
import com.stripe.android.lpmfoundations.paymentmethod.definitions.KonbiniDefinition
import com.stripe.android.lpmfoundations.paymentmethod.definitions.LinkCardBrandDefinition
import com.stripe.android.lpmfoundations.paymentmethod.definitions.MobilePayDefinition
import com.stripe.android.lpmfoundations.paymentmethod.definitions.MultibancoDefinition
import com.stripe.android.lpmfoundations.paymentmethod.definitions.OxxoDefinition
Expand Down Expand Up @@ -62,6 +63,7 @@ internal object PaymentMethodRegistry {
InstantDebitsDefinition,
KlarnaDefinition,
KonbiniDefinition,
LinkCardBrandDefinition,
MobilePayDefinition,
MultibancoDefinition,
OxxoDefinition,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.stripe.android.lpmfoundations.paymentmethod.definitions

import com.stripe.android.lpmfoundations.luxe.SupportedPaymentMethod
import com.stripe.android.lpmfoundations.paymentmethod.AddPaymentMethodRequirement
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodDefinition
import com.stripe.android.lpmfoundations.paymentmethod.PaymentMethodMetadata
import com.stripe.android.lpmfoundations.paymentmethod.UiDefinitionFactory
import com.stripe.android.model.PaymentMethod
import com.stripe.android.uicore.elements.FormElement
import com.stripe.android.ui.core.R as PaymentsUiCoreR

internal object LinkCardBrandDefinition : PaymentMethodDefinition {

override val type: PaymentMethod.Type = PaymentMethod.Type.Link

override val supportedAsSavedPaymentMethod: Boolean = false

override fun requirementsToBeUsedAsNewPaymentMethod(
hasIntentToSetup: Boolean
): Set<AddPaymentMethodRequirement> = setOf(
AddPaymentMethodRequirement.FinancialConnectionsSdk,
AddPaymentMethodRequirement.LinkCardBrand,
)

override fun requiresMandate(metadata: PaymentMethodMetadata): Boolean = true

override fun uiDefinitionFactory(): UiDefinitionFactory = LinkCardBrandDefinitionFactory
}

private object LinkCardBrandDefinitionFactory : UiDefinitionFactory.Simple {

override fun createSupportedPaymentMethod(): SupportedPaymentMethod {
return SupportedPaymentMethod(
code = InstantDebitsDefinition.type.code,
displayNameResource = PaymentsUiCoreR.string.stripe_paymentsheet_payment_method_instant_debits,
iconResource = PaymentsUiCoreR.drawable.stripe_ic_paymentsheet_pm_bank,
iconRequiresTinting = true,
lightThemeIconUrl = null,
darkThemeIconUrl = null,
)
}

// Link Card Brand uses its own mechanism, not these form elements.
override fun createFormElements(
metadata: PaymentMethodMetadata,
arguments: UiDefinitionFactory.Arguments,
): List<FormElement> {
return emptyList()
}
}

0 comments on commit 2a31812

Please sign in to comment.