#Jordan-PaymentSheet

1 messages ยท Page 1 of 1 (latest)

grizzled elbow
#

Hi there! Hmm let me take a look.

latent thistle
#

Just to add some color, I'm specifically referring to the paymentSheetFlowController.presentPaymentOptions() callback. When this returns, it seems that the paymentSheetFC returns with a paymentOption even if the user has not selected one.

grizzled elbow
#

Gotcha, I'm not super familiar with this flow. Asking a colleague and I'll get back to ya

latent thistle
#

Okay thanks- much appreciated

latent thistle
#

I'll add some further clarification:

  • If the PaymentSheetFC has been instantiated with payment_method_types = ["card"], but the user has no existing payment methods, cancelling the PaymentSheet will give us paymentOption == nil (expected)
  • If the PaymentSheetFC has been instantiated with payment_method_types = ["card"], but the user has existing payment methods, cancelling the PaymentSheet will give us paymentOption == [some card] (unexpected)
  • If the PaymentSheetFC has been instantiated with payment_method_types = ["afterpay_clearpay"], cancelling the PaymentSheet will give us paymentOption == [afterpay/clearpay] (very unexpected, as BNPL payment options cannot be saved on the Customer object)
grizzled elbow
#

Thanks for the added detail. A colleague is spinning up a test to check this out but will take a few minutes.

latent thistle
#

Okay thanks!

latent thistle
#

I believe PaymentSheetResult is only available upon confirmation of the PaymentSheetFC (confirming the underlying Intent here). canceled in this case refers to any cancellation state in the authorization flow, correct?

#

So we want to do something before that to detect if we should even call .confirm() in the first place

terse fulcrum
#

๐Ÿ‘‹ Hopping in - give me a minute to catch up

latent thistle
#

We are calling paymentSheetFC.presentPaymentOptions(from: self) { in ... }, and the expected the completion block type for this argument is () -> (), so I'm not sure that PaymentSheetResult is available here

#

Also, I'd just like to clarify that we are using PaymentSheet.FlowController, and not PaymentSheet

terse fulcrum
#

Yup, you're right - for presentPaymentOptions you don't have PaymentSheetResult available there. Looking to see what options you have here - but just so I can better understand, why is knowing the distinction between exiting through the "x" button, and exiting because a payment method so important for your integration?

latent thistle
#

We have a slightly weird Stripe configuration for mainly business reasons. I won't bore you with unrelated details, but we basically use SetupIntents-only to enable checkout on the client, and we need to use PaymentSheet.FlowController to get what we want. We can't use SetupIntents for BNPL payment methods, so we are using a PaymentIntent with capture_method = manual here, and instantiating a PaymentSheetFC using this PaymentIntent. For our SetupIntent use case (normal CCs), we confirm the SetupIntent immediately after Sheet dismissal (unless the PaymentSheetFC says that there is no paymentOption attached upon dismissal (see cases above)). But we basically confirm the SetupIntent each time if the user has a previous payment method attached upon dismissal (with no real effect here). We should not, however, confirm the PaymentIntent in the case of our BNPL PaymentSheetFC because we can't be sure the user actually tapped Continue and selected a BNPL payment method, or just tapped 'X' to cancel the sheet.

#

So in the BNPL case, each dismissal of the PaymentSheetFC is giving us a paymentOption (Afterpay, in this case), when in reality the user has not actually selected any option. And we are looking at the absence of paymentOption to detect whether or not we can skip any further steps

terse fulcrum
#

So if I'm understanding right, the biggest issue here is that payment_method_types = ["afterpay_clearpay"] is giving you back an afterpay PaymentOption even though it's impossible for the customer to have that saved (since you can't save these payment method types for future use). And your request to be able to know when the cancel button is selected it just to get around this, right?

latent thistle
#

Yep, that's correct

#

And in the case of payment_method_types = ["card"], I guess it's just confusing that the PaymentSheetFC is giving us back a paymentOption in the case that the user has existing saved payment_methods, but has tapped 'X', not selecting an option. So it's similar in that way

#

But for payment_method_types = ["card"] where the user has no saved payment_methods, the PaymentSheetFC gives us paymentOption == nil upon dismissal via 'X', which is what I would expect. So it's confusing why it won't do this for BNPL payment methods, which cannot be saved to a Customer.

terse fulcrum
#

The card case is expected I believe though - if they have saved payment methods we'll pre-fill to one of their saved ones if available.

latent thistle
#

Yeah we have a workaround for that (we just confirm the SetupIntent anyways, even if it has been "chosen" by default). We cannot do that for BNPL

terse fulcrum
#

Another question - when you call confirm() with a BNPL payment option (the one pre-populated after clicking 'x'), what error do you get?

latent thistle
#

paymentOption is a cosmetic object, from what I understand, but because we can't detect if this choice was intentional, I believe we get an error

#

I can check- one sec

#

Okay, it looks like it just succeeds

#

Which is not good

terse fulcrum
#

Do you mind sharing that PI so I can take a look?

latent thistle
#

Sure one sec- I need to make a new one

#

pm_1L6jsm2aMfcdR0nnEbmAjZCP / pi_3L6jsg2aMfcdR0nn0HVLWl59

#

And to be clear, after cancelling via 'X', we confirm the PaymentIntent/PaymentSheetFC, and then I see the Stripe test page where I authorize payment

#

But we don't want customers who cancelled to even see this page

terse fulcrum
#

I think this kind of behaves how you want it to though - you can see in the PI that it's not using a saved Payment Method at all. Since afterpay was the only option on the PI, presentPaymentOptions default to it. It's not defaulting to a saved PM, it's using information already available on the customer to confirm the payment

latent thistle
#

No, it does not work how I would expect it to work here- we do not want to confirm this PaymentIntent if the user cancels via 'X'. But because we have nothing to detect this case, we proceed with confirmation

#

defaulting to a saved PM in the case of payment_method_types = ["card"] is categorically different here, albeit still annoying. The user has not themselves chosen a BNPL payment method in this case, yet the PaymentSheetFC says that they have

#

IMO, it seems like what is going on here is that there is a bug in PaymentSheet.FlowController here (while there may not be in PaymentSheet). PaymentSheetFC should give us either a simple boolean or a full PaymentSheetResult response in the callback to paymentSheetFC.presentPaymentOptions(from: self) { in ... }

terse fulcrum
#

To clarify - I know this doesn't work how you'd specifically expect it to. I'm just trying to reason out why they may have implemented it this way. My guess is that we made a product decision - that since after afterpay is the only option on that PI we expect that if a user wants to pay then we can default to afterpay because there is really no other option for them

latent thistle
#

One more thing to clarify: We have separated out our payment_method_types for each use-case (normal CCs, and BNPL). So we are instantiating PaymentSheetFC with payment_method_types = ["card"] and separately payment_method_types = ["afterpay_clearpay"] for each case, but never payment_method_types = ["afterpay_clearpay", "card"].

#

Does that make sense? I'm not sure if that's relevant

#

There is currently no way to detect if a user has cancelled the PaymentSheetFC whilst using payment_method_types = ["afterpay_clearpay"], so I have no idea what we can do to not confirm this PaymentSheetFC/PaymentIntent at this point

#

The "defaulting to the last saved card" behavior with "card" is a product decision (perhaps one that assumes too much, but oh well), but this behavior with "afterpay_clearpay" honestly seems like a bug. How can we safely default to a payment method that the user has not themselves chosen, and that can't ever be saved to their Customer object?

terse fulcrum
#

How can we safely default to a payment method that the user has not themselves chosen, and that can't ever be saved to their Customer object?
Even though the user has not explicitly chosen afterpay, they should still have another opportunity to decide whether to continue paying since they can choose whether or not continue with confirm (assuming you have this tied to a button). If you're calling confirm() immediately after presentPaymentOptions is done, then that isn't really how this multi-step flow is intended to be used.

I do see what you're saying, but I do think this was more of a product decision - I'd recommend talking to support (https://support.stripe.com/contact) to see if they may be open to changing it

latent thistle
#

Even in the first case (separating the steps), cancelling the Sheet will still result in our UI showing that they selected the BNPL option (which wouldn't be true in this case). There is no way to detect otherwise

terse fulcrum
#

It would still show as selected, but does that matter? They can just choose to not continue with payment and exit the flow?

latent thistle
#

Well presumably they wouldn't have even "entered their info" yet, so yes it would be very odd to show this to the user

#

And the point of using PaymentSheetFC was to have as much granular control over different states during checkout (while also using the Stripe pre-built UI), so it's weird that seems to be no way to detect state here. If we have a prominent, separate "Pay Later" button on the checkout page, I would imagine many users just want to explore it to see what it is/means, while not intending to use it

terse fulcrum
#

I think we're talking past each other - again, I do see why you want this but from my understanding of the ios sdk it just wasn't designed with what you wanted in mind. Even with the "Pay Later" situation you describe, I think we still handle that because we expect you to have a separate button to actually finish the process.The things you want are feature requests, and going to support is the best way to request them.

latent thistle
#

Okay, is there a way to pass along the context from this thread so that I don't need to write it again?

terse fulcrum
#

You can always just link to thread

latent thistle
#

Okay

#

Well thanks for your time Karbi!

terse fulcrum
#

๐Ÿ‘‹ sorry it wasn't exactly the answer you were looking for