stripe / stripe-ios

Stripe iOS SDK
https://stripe.com
MIT License
2.09k stars 976 forks source link

setDefaultPaymentMethod not working #1261

Closed gadget-man closed 5 years ago

gadget-man commented 5 years ago

I see 16.0.2 has been released including setDefaultPaymentMethod as referenced in #1245.

I've successfully retrieved the default payment method for invoices (saved to Stripe.PaymentMethod) but when I pass the variable as follows: paymentContext.defaultPaymentMethod = Stripe.PaymentMethod paymentContext.presentPaymentOptionsViewController()

The app crashes when I press the payment method button: -[STPPaymentContext setDefaultPaymentMethod:]: unrecognized selector sent to instance 0x2803ffb80

Is it not working or am I mis-understanding the issue?

yuki-stripe commented 5 years ago

Thanks for the report @needlerp! I'm not able to repro this, could you give more details including the stack trace?

gadget-man commented 5 years ago

I have a UIButton paymentCard in my VC. On VC load I call a function to get the default payment_method for the customer, which is saved to Stripe.PaymentMethod.

On clicking the paymentCard button the following is called: @IBAction func paymentCard(_ sender: Any) { STPPaymentConfiguration.shared().requiredBillingAddressFields = .full paymentContext.defaultPaymentMethod = Stripe.PaymentMethod paymentContext.presentPaymentOptionsViewController() } As soon as the paymentCard button is pressed, the app crashes with the following: 2019-07-30 18:01:28.184137+0100 iParcelBox-DEV[31936:10277701] -[STPPaymentContext setDefaultPaymentMethod:]: unrecognized selector sent to instance 0x6000012ca4c0 2019-07-30 18:01:28.232255+0100 iParcelBox-DEV[31936:10277701] Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[STPPaymentContext setDefaultPaymentMethod:]: unrecognized selector sent to instance 0x6000012ca4c0' First throw call stack: ( 0 CoreFoundation 0x00000001124fb8db exceptionPreprocess + 331 1 libobjc.A.dylib 0x0000000111a9eac5 objc_exception_throw + 48 2 CoreFoundation 0x0000000112519c94 -[NSObject(NSObject) doesNotRecognizeSelector:] + 132 3 CoreFoundation 0x0000000112500623 __forwarding + 1443 4 CoreFoundation 0x0000000112502418 _CF_forwarding_prep_0 + 120 5 iParcelBox-DEV 0x00000001080586e4 $s14iParcelBox_DEV29UserDetailTableViewControllerC11paymentCardyyypF + 260 6 iParcelBox-DEV 0x000000010805876c $s14iParcelBox_DEV29UserDetailTableViewControllerC11paymentCardyyypFTo + 76 7 UIKitCore 0x000000011c137624 -[UIApplication sendAction:to:from:forEvent:] + 83 8 UIKitCore 0x000000011bb8c8d5 -[UIControl sendAction:to:forEvent:] + 67 9 UIKitCore 0x000000011bb8cbf2 -[UIControl _sendActionsForEvents:withEvent:] + 450 10 UIKitCore 0x000000011bb8bba8 -[UIControl touchesEnded:withEvent:] + 583 11 UIKitCore 0x000000011bd18bfd _UIGestureEnvironmentUpdate + 10367 12 UIKitCore 0x000000011bd1633c -[UIGestureEnvironment _deliverEvent:toGestureRecognizers:usingBlock:] + 478 13 UIKitCore 0x000000011bd160ca -[UIGestureEnvironment _updateForEvent:window:] + 200 14 UIKitCore 0x000000011c171bb4 -[UIWindow sendEvent:] + 4057 15 UIKitCore 0x000000011c15030e -[UIApplication sendEvent:] + 356 16 UIKitCore 0x000000011c2202b3 dispatchPreprocessedEventFromEventQueue + 3232 17 UIKitCore 0x000000011c222bd9 handleEventQueueInternal + 5911 18 CoreFoundation 0x0000000112462db1 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17 19 CoreFoundation 0x0000000112462633 CFRunLoopDoSources0 + 243 20 CoreFoundation 0x000000011245ccef CFRunLoopRun + 1231 21 CoreFoundation 0x000000011245c4d2 CFRunLoopRunSpecific + 626 22 GraphicsServices 0x00000001152512fe GSEventRunModal + 65 23 UIKitCore 0x000000011c135fc2 UIApplicationMain + 140 24 iParcelBox-DEV 0x000000010810d13b main + 75 25 libdyld.dylib 0x0000000113b8f541 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

yuki-stripe commented 5 years ago

@needlerp Huh, this is super weird, STPPaymentContext definitely has this property - https://github.com/stripe/stripe-ios/blob/d775c6b650f56d2f1c8aa48365939f8b9ee6d339/Stripe/PublicHeaders/STPPaymentContext.h#L144. What's the value of STPSDKVersion? Could you try re-installing the Stripe SDK?

yuki-stripe commented 5 years ago

As an aside, I'm not sure setting the defaultPaymentMethod at this point will have an effect unless you call retryLoading afterwards. You could also set defaultPaymentMethod immediately after initializing STPPaymentContext.

gadget-man commented 5 years ago

Thanks, I removed the Stripe SDK from Cocoapods then reinstalled it, and it seems to be working now. Also thanks for the tip on retryLoading! It seems to be working great now.

Is there a similar option in the Android SDK that I can point my developers to for the same outcome on Android?

yuki-stripe commented 5 years ago

@needlerp Glad to hear it!

There's no equivalent yet on Android, we're working on this behavior in https://github.com/stripe/stripe-android/pull/1263. You can comment/raise an issue over there!

rromanchuk commented 5 years ago

Is this only available to STPPaymentOptionsViewController, or can I utilize this at a lower level as well? For example lets say i'm managing payment methods myself and have a collection of paymentMethods

customerContext.listPaymentMethodsForCustomer { (paymentMethods, error) in
    guard let paymentMethods = paymentMethods else {
        return
    }
    self.payments = paymentMethods
}

Is there some equivalent for customerContext.setDefaultPaymentMethod()?

rromanchuk commented 5 years ago
let paymentContext = STPPaymentContext(customerContext: customerContext)
paymentContext.defaultPaymentMethod

The Stripe ID of a payment method to display as the default pre-selected option. Customer doesn't have a default payment method property, but you can store one (in its metadata, for example) and set this property accordingly.

This is odd to me, where does customer.invoice_settings.default_payment_method come into play? It's annoying that i can get this far on the client but will end up have to building a client/server REST api to manage these user preferences. It would be ideal if POST /v1/payment_method operations accepted a make_default that automatically updated this value at the customer level. It's difficult to grok because it's a departure of how sources and default sources used to work. If i have a off_sesion setupintent i should be able to make that payment set to customer.invoice_settings.default_payment_method without rolling my own state machine

yuki-stripe commented 5 years ago

Hi @rromanchuk ,

I hear you, it's annoying. I would try storing the desired default payment method id in Customer.metadata (https://stripe.com/docs/api/customers/object#customer_object-metadata) to avoid having to build the REST API like you said.

customer.invoice_settings.default_payment_method is related to Billing/subscriptions (https://stripe.com/docs/api/subscriptions/create#create_subscription-default_payment_method).

rromanchuk commented 5 years ago

@yuki-stripe https://stripe.com/docs/api/invoices/object#invoice_object-default_payment_method

ID of the default payment method for the invoice. It must belong to the customer associated with the invoice. If not set, defaults to the subscription’s default payment method, if any, or to the default payment method in the customer’s invoice settings.

rromanchuk commented 5 years ago

@yuki-stripe is there any way to update metadata from the client using STPCustomerContext the only property modifications i see are updateCustomerWithShippingAddress

yuki-stripe commented 5 years ago

@rromanchuk

There isn't, I think you could make a category to do this.