Skip to content

Commit

Permalink
Enable Afterpay in Payment Sheet (#4492)
Browse files Browse the repository at this point in the history
  • Loading branch information
brnunes-stripe authored Jan 5, 2022
1 parent cb8df75 commit bbffc21
Show file tree
Hide file tree
Showing 14 changed files with 354 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ internal sealed interface SIRequirement : Requirement
@Parcelize
internal object Delayed : PIRequirement, SIRequirement

/**
* The Payment Method requires a shipping address in the Payment Intent.
* The fields required are name, address line 1, country, and postal code.
*/
@Parcelize
internal object ShippingAddress : PIRequirement

@Parcelize
internal data class PaymentMethodRequirements(

Expand Down Expand Up @@ -212,12 +219,7 @@ internal val GiropayRequirement = PaymentMethodRequirements(
* This defines the requirements for usage as a Payment Method.
*/
internal val AfterpayClearpayRequirement = PaymentMethodRequirements(
/**
* This is null until we have after cancellation support. When we have cancellation support
* this will require Shipping name, address line 1, address country, and postal
*/
piRequirements = null,

piRequirements = setOf(ShippingAddress),
/**
* SetupIntents are not supported by this payment method, in addition,
* setup intents do not have shipping information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ import com.stripe.android.paymentsheet.forms.GiropayRequirement
import com.stripe.android.paymentsheet.forms.IdealRequirement
import com.stripe.android.paymentsheet.forms.KlarnaRequirement
import com.stripe.android.paymentsheet.forms.P24Requirement
import com.stripe.android.paymentsheet.forms.PIRequirement
import com.stripe.android.paymentsheet.forms.PaymentMethodRequirements
import com.stripe.android.paymentsheet.forms.PaypalRequirement
import com.stripe.android.paymentsheet.forms.Requirement
import com.stripe.android.paymentsheet.forms.SIRequirement
import com.stripe.android.paymentsheet.forms.SepaDebitRequirement
import com.stripe.android.paymentsheet.forms.ShippingAddress
import com.stripe.android.paymentsheet.forms.SofortRequirement
import com.stripe.android.ui.core.elements.LayoutFormDescriptor
import com.stripe.android.ui.core.elements.LayoutSpec
Expand Down Expand Up @@ -75,6 +77,7 @@ internal sealed class SupportedPaymentMethod(
SaveForFutureUseSpec(emptyList())
)
)

@Parcelize
object Bancontact : SupportedPaymentMethod(
PaymentMethod.Type.Bancontact,
Expand All @@ -84,6 +87,7 @@ internal sealed class SupportedPaymentMethod(
BancontactParamKey,
BancontactForm
)

@Parcelize
object Sofort : SupportedPaymentMethod(
PaymentMethod.Type.Sofort,
Expand All @@ -93,6 +97,7 @@ internal sealed class SupportedPaymentMethod(
SofortParamKey,
SofortForm
)

@Parcelize
object Ideal : SupportedPaymentMethod(
PaymentMethod.Type.Ideal,
Expand All @@ -102,6 +107,7 @@ internal sealed class SupportedPaymentMethod(
IdealParamKey,
IdealForm
)

@Parcelize
object SepaDebit : SupportedPaymentMethod(
PaymentMethod.Type.SepaDebit,
Expand All @@ -111,6 +117,7 @@ internal sealed class SupportedPaymentMethod(
SepaDebitParamKey,
SepaDebitForm
)

@Parcelize
object Eps : SupportedPaymentMethod(
PaymentMethod.Type.Eps,
Expand All @@ -120,6 +127,7 @@ internal sealed class SupportedPaymentMethod(
EpsParamKey,
EpsForm
)

@Parcelize
object P24 : SupportedPaymentMethod(
PaymentMethod.Type.P24,
Expand All @@ -129,6 +137,7 @@ internal sealed class SupportedPaymentMethod(
P24ParamKey,
P24Form
)

@Parcelize
object Giropay : SupportedPaymentMethod(
PaymentMethod.Type.Giropay,
Expand All @@ -138,6 +147,7 @@ internal sealed class SupportedPaymentMethod(
GiropayParamKey,
GiropayForm
)

@Parcelize
object AfterpayClearpay : SupportedPaymentMethod(
PaymentMethod.Type.AfterpayClearpay,
Expand All @@ -147,6 +157,7 @@ internal sealed class SupportedPaymentMethod(
AfterpayClearpayParamKey,
AfterpayClearpayForm
)

@Parcelize
object Klarna : SupportedPaymentMethod(
PaymentMethod.Type.Klarna,
Expand All @@ -156,6 +167,7 @@ internal sealed class SupportedPaymentMethod(
KlarnaParamKey,
KlarnaForm
)

@Parcelize
object PayPal : SupportedPaymentMethod(
PaymentMethod.Type.PayPal,
Expand Down Expand Up @@ -208,7 +220,7 @@ internal sealed class SupportedPaymentMethod(
return when (stripeIntent) {
is PaymentIntent -> {
if ((stripeIntent.isSetupFutureUsageSet())) {
if (supportsPaymentIntentSfuSet(config)
if (supportsPaymentIntentSfuSet(stripeIntent, config)
) {
merchantRequestedSave
} else {
Expand All @@ -222,6 +234,7 @@ internal sealed class SupportedPaymentMethod(
)
-> userSelectableSave
supportsPaymentIntentSfuNotSettable(
stripeIntent,
config
) -> oneTimeUse
else -> null
Expand Down Expand Up @@ -252,7 +265,7 @@ internal sealed class SupportedPaymentMethod(
private fun supportsSetupIntent(
config: PaymentSheet.Configuration?
) = requirement.confirmPMFromCustomer == true &&
checkRequirements(requirement.siRequirements, config)
checkSetupIntentRequirements(requirement.siRequirements, config)

/**
* This checks if there is support using this payment method when SFU
Expand All @@ -261,18 +274,20 @@ internal sealed class SupportedPaymentMethod(
* a consistent user experience.
*/
private fun supportsPaymentIntentSfuSet(
paymentIntent: PaymentIntent,
config: PaymentSheet.Configuration?
) = requirement.confirmPMFromCustomer == true &&
checkRequirements(requirement.siRequirements, config) &&
checkRequirements(requirement.piRequirements, config)
checkSetupIntentRequirements(requirement.siRequirements, config) &&
checkPaymentIntentRequirements(requirement.piRequirements, paymentIntent, config)

/**
* This detects if there is support with using this PM with the PI
* where SFU is not settable by the user.
*/
private fun supportsPaymentIntentSfuNotSettable(
paymentIntent: PaymentIntent,
config: PaymentSheet.Configuration?
) = checkRequirements(requirement.piRequirements, config)
) = checkPaymentIntentRequirements(requirement.piRequirements, paymentIntent, config)

/**
* This checks to see if this PM is supported with the given
Expand All @@ -285,23 +300,42 @@ internal sealed class SupportedPaymentMethod(
* and seeing the saved PMs associate with their customer object.
*/
private fun supportsPaymentIntentSfuSettable(
stripeIntent: PaymentIntent,
paymentIntent: PaymentIntent,
config: PaymentSheet.Configuration?
) = config?.customer != null &&
requirement.confirmPMFromCustomer == true &&
checkRequirements(requirement.piRequirements, config) &&
checkRequirements(requirement.siRequirements, config)
checkPaymentIntentRequirements(requirement.piRequirements, paymentIntent, config) &&
checkSetupIntentRequirements(requirement.siRequirements, config)

/**
* Verifies that all Setup Intent [requirements] are met.
*/
private fun checkSetupIntentRequirements(
requirements: Set<SIRequirement>?,
config: PaymentSheet.Configuration?
) =
requirements?.map { requirement ->
when (requirement) {
Delayed -> config?.allowsDelayedPaymentMethods == true
}
}?.contains(false) == false

/**
* Currently the only required requirement in the SDK is Delayed PMs
* Verifies that all Payment Intent [requirements] are met.
*/
private fun checkRequirements(
requirements: Set<Requirement>?,
private fun checkPaymentIntentRequirements(
requirements: Set<PIRequirement>?,
paymentIntent: PaymentIntent,
config: PaymentSheet.Configuration?
) =
requirements?.map { requirement ->
when (requirement) {
Delayed -> config?.allowsDelayedPaymentMethods == true
ShippingAddress ->
paymentIntent.shipping?.name != null &&
paymentIntent.shipping?.address?.line1 != null &&
paymentIntent.shipping?.address?.country != null &&
paymentIntent.shipping?.address?.postalCode != null
}
}?.contains(false) == false

Expand All @@ -317,7 +351,17 @@ internal sealed class SupportedPaymentMethod(
*/
@VisibleForTesting
internal val exposedPaymentMethods = listOf(
Card, Bancontact, Sofort, Ideal, SepaDebit, Eps, Giropay, P24, Klarna, PayPal
Card,
Bancontact,
Sofort,
Ideal,
SepaDebit,
Eps,
Giropay,
P24,
Klarna,
PayPal,
AfterpayClearpay
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,28 +125,31 @@ class SupportedPaymentMethodTest {
val customerStates = setOf(true, false)
val setupFutureUsage = setOf(StripeIntent.Usage.OffSession, StripeIntent.Usage.OnSession, null)
val allowsDelayedPayment = setOf(true, false)

customerStates.forEach { customer ->
setupFutureUsage.forEach { usage ->
allowsDelayedPayment.forEach { delayed ->
scenarios.addAll(
listOf(
PaymentIntentTestInput(
hasCustomer = customer,
intentPMs = setOf(SupportedPaymentMethod.Card.type.code),
intentSetupFutureUsage = usage,
intentHasShipping = false,
allowsDelayedPayment = delayed
),
PaymentIntentTestInput(
hasCustomer = customer,
intentPMs = setOf(SupportedPaymentMethod.Card.type.code, SupportedPaymentMethod.Eps.type.code),
intentSetupFutureUsage = usage,
intentHasShipping = false,
allowsDelayedPayment = delayed
val hasShippingAddress = setOf(false, true)

hasShippingAddress.forEach { hasShipping ->
customerStates.forEach { customer ->
setupFutureUsage.forEach { usage ->
allowsDelayedPayment.forEach { delayed ->
scenarios.addAll(
listOf(
PaymentIntentTestInput(
hasCustomer = customer,
intentPMs = setOf(SupportedPaymentMethod.Card.type.code),
intentSetupFutureUsage = usage,
intentHasShipping = hasShipping,
allowsDelayedPayment = delayed
),
PaymentIntentTestInput(
hasCustomer = customer,
intentPMs = setOf(SupportedPaymentMethod.Card.type.code, SupportedPaymentMethod.Eps.type.code),
intentSetupFutureUsage = usage,
intentHasShipping = hasShipping,
allowsDelayedPayment = delayed
)
)
)
)
}
}
}
}
Expand Down Expand Up @@ -187,7 +190,8 @@ class SupportedPaymentMethodTest {

fun getIntent(lpm: SupportedPaymentMethod) = when (intentHasShipping) {
false ->
PaymentIntentFixtures.PI_OFF_SESSION.copy(
PaymentIntentFixtures.PI_WITH_SHIPPING.copy(
shipping = null,
setupFutureUsage = intentSetupFutureUsage,
paymentMethodTypes = intentPMs.plus(lpm.type.code).toList()
)
Expand Down
24 changes: 24 additions & 0 deletions paymentsheet/src/test/resources/afterpay_clearpay-support.csv
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ afterpay_clearpay, false, true, null, false, card/afterpay_clearpay, false, fals
afterpay_clearpay, false, true, null, false, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, false, null, false, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, false, null, false, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, true, off_session, true, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, true, off_session, true, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, false, off_session, true, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, false, off_session, true, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, true, on_session, true, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, true, on_session, true, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, false, on_session, true, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, false, on_session, true, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, true, true, null, true, card/afterpay_clearpay, false, true, oneTime, true
afterpay_clearpay, true, true, null, true, card/eps/afterpay_clearpay, false, true, oneTime, true
afterpay_clearpay, true, false, null, true, card/afterpay_clearpay, false, true, oneTime, true
afterpay_clearpay, true, false, null, true, card/eps/afterpay_clearpay, false, true, oneTime, true
afterpay_clearpay, false, true, off_session, true, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, true, off_session, true, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, false, off_session, true, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, false, off_session, true, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, true, on_session, true, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, true, on_session, true, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, false, on_session, true, card/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, false, on_session, true, card/eps/afterpay_clearpay, false, false, not available, false
afterpay_clearpay, false, true, null, true, card/afterpay_clearpay, false, true, oneTime, true
afterpay_clearpay, false, true, null, true, card/eps/afterpay_clearpay, false, true, oneTime, true
afterpay_clearpay, false, false, null, true, card/afterpay_clearpay, false, true, oneTime, true
afterpay_clearpay, false, false, null, true, card/eps/afterpay_clearpay, false, true, oneTime, true
24 changes: 24 additions & 0 deletions paymentsheet/src/test/resources/bancontact-support.csv
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ bancontact, false, true, null, false, card/bancontact, false, true, oneTime, tru
bancontact, false, true, null, false, card/eps/bancontact, false, true, oneTime, true
bancontact, false, false, null, false, card/bancontact, false, true, oneTime, true
bancontact, false, false, null, false, card/eps/bancontact, false, true, oneTime, true
bancontact, true, true, off_session, true, card/bancontact, false, false, not available, false
bancontact, true, true, off_session, true, card/eps/bancontact, false, false, not available, false
bancontact, true, false, off_session, true, card/bancontact, false, false, not available, false
bancontact, true, false, off_session, true, card/eps/bancontact, false, false, not available, false
bancontact, true, true, on_session, true, card/bancontact, false, false, not available, false
bancontact, true, true, on_session, true, card/eps/bancontact, false, false, not available, false
bancontact, true, false, on_session, true, card/bancontact, false, false, not available, false
bancontact, true, false, on_session, true, card/eps/bancontact, false, false, not available, false
bancontact, true, true, null, true, card/bancontact, false, true, oneTime, true
bancontact, true, true, null, true, card/eps/bancontact, false, true, oneTime, true
bancontact, true, false, null, true, card/bancontact, false, true, oneTime, true
bancontact, true, false, null, true, card/eps/bancontact, false, true, oneTime, true
bancontact, false, true, off_session, true, card/bancontact, false, false, not available, false
bancontact, false, true, off_session, true, card/eps/bancontact, false, false, not available, false
bancontact, false, false, off_session, true, card/bancontact, false, false, not available, false
bancontact, false, false, off_session, true, card/eps/bancontact, false, false, not available, false
bancontact, false, true, on_session, true, card/bancontact, false, false, not available, false
bancontact, false, true, on_session, true, card/eps/bancontact, false, false, not available, false
bancontact, false, false, on_session, true, card/bancontact, false, false, not available, false
bancontact, false, false, on_session, true, card/eps/bancontact, false, false, not available, false
bancontact, false, true, null, true, card/bancontact, false, true, oneTime, true
bancontact, false, true, null, true, card/eps/bancontact, false, true, oneTime, true
bancontact, false, false, null, true, card/bancontact, false, true, oneTime, true
bancontact, false, false, null, true, card/eps/bancontact, false, true, oneTime, true
24 changes: 24 additions & 0 deletions paymentsheet/src/test/resources/card-support.csv
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ card, false, true, null, false, card, true, true, oneTime, true
card, false, true, null, false, card/eps, true, true, oneTime, true
card, false, false, null, false, card, true, true, oneTime, true
card, false, false, null, false, card/eps, true, true, oneTime, true
card, true, true, off_session, true, card, true, true, merchantRequiredSave, true
card, true, true, off_session, true, card/eps, true, true, merchantRequiredSave, true
card, true, false, off_session, true, card, true, true, merchantRequiredSave, true
card, true, false, off_session, true, card/eps, true, true, merchantRequiredSave, true
card, true, true, on_session, true, card, true, true, merchantRequiredSave, true
card, true, true, on_session, true, card/eps, true, true, merchantRequiredSave, true
card, true, false, on_session, true, card, true, true, merchantRequiredSave, true
card, true, false, on_session, true, card/eps, true, true, merchantRequiredSave, true
card, true, true, null, true, card, true, true, userSelectedSave, true
card, true, true, null, true, card/eps, true, true, userSelectedSave, true
card, true, false, null, true, card, true, true, userSelectedSave, true
card, true, false, null, true, card/eps, true, true, userSelectedSave, true
card, false, true, off_session, true, card, true, true, merchantRequiredSave, true
card, false, true, off_session, true, card/eps, true, true, merchantRequiredSave, true
card, false, false, off_session, true, card, true, true, merchantRequiredSave, true
card, false, false, off_session, true, card/eps, true, true, merchantRequiredSave, true
card, false, true, on_session, true, card, true, true, merchantRequiredSave, true
card, false, true, on_session, true, card/eps, true, true, merchantRequiredSave, true
card, false, false, on_session, true, card, true, true, merchantRequiredSave, true
card, false, false, on_session, true, card/eps, true, true, merchantRequiredSave, true
card, false, true, null, true, card, true, true, oneTime, true
card, false, true, null, true, card/eps, true, true, oneTime, true
card, false, false, null, true, card, true, true, oneTime, true
card, false, false, null, true, card/eps, true, true, oneTime, true
Loading

0 comments on commit bbffc21

Please sign in to comment.