Skip to content
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

Enable Afterpay in Payment Sheet #4492

Merged
merged 4 commits into from
Jan 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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