#Jordan-PaymentSheet
1 messages ยท Page 1 of 1 (latest)
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.
Gotcha, I'm not super familiar with this flow. Asking a colleague and I'll get back to ya
Okay thanks- much appreciated
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)
Thanks for the added detail. A colleague is spinning up a test to check this out but will take a few minutes.
Okay thanks!
Okay so it sounds like instead of using paymentOption here you can rely on the PaymentSheetResult. Here is an example that we have that relies on PaymentSheetResult and, in this case if they dismiss the sheet from the "x", it would be canceled: https://github.com/stripe/stripe-ios/blob/master/Example/PaymentSheet Example/PaymentSheet Example/PaymentSheet Example/ExampleSwiftUIViews.swift#L37-L50
Looks like the flow from that example starts here: https://github.com/stripe/stripe-ios/blob/master/Example/PaymentSheet Example/PaymentSheet Example/PaymentSheet Example/ExampleSwiftUICustomPaymentFlow.swift#L112 which uses https://github.com/stripe/stripe-ios/blob/master/Example/PaymentSheet Example/PaymentSheet Example/PaymentSheet Example/ExampleSwiftUICustomPaymentFlow.swift#L45-L47 and then https://github.com/stripe/stripe-ios/blob/master/Example/PaymentSheet Example/PaymentSheet Example/PaymentSheet Example/ExampleSwiftUIViews.swift#L36-L55
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
๐ Hopping in - give me a minute to catch up
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
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?
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
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?
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.
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.
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
Another question - when you call confirm() with a BNPL payment option (the one pre-populated after clicking 'x'), what error do you get?
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
Do you mind sharing that PI so I can take a look?
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
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
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 ... }
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
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?
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
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
It would still show as selected, but does that matter? They can just choose to not continue with payment and exit the flow?
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
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.
Okay, is there a way to pass along the context from this thread so that I don't need to write it again?
You can always just link to thread
๐ sorry it wasn't exactly the answer you were looking for