flutter_stripe icon indicating copy to clipboard operation
flutter_stripe copied to clipboard

Flutter Web Stripe.instance.createPaymentMethod Issue

Open glennarixxi opened this issue 3 years ago • 21 comments

When I execute this:

final paymentMethod = await Stripe.instance.createPaymentMethod(PaymentMethodParams.card( paymentMethodData: PaymentMethodData(billingDetails: billingDetails, shippingDetails: shippingDetails), ));

I receive an Unimplemented Error

Where:

final billingDetails = BillingDetails( email: '[email protected]', phone: '+48888000888', address: Address( city: 'Houston', country: 'US', line1: '1459 Circle Drive', line2: '', state: 'Texas', postalCode: '77063', ), ); // mocked data for tests

  final shippingDetails = ShippingDetails(
    phone: '+48888000888',
    address: Address(
      city: 'Houston',
      country: 'US',
      line1: '1459  Circle Drive',
      line2: '',
      state: 'Texas',
      postalCode: '77063',
    ),
  );

Error comes from:

web_stripe.dart

@override Future<PaymentMethod> createPaymentMethod( PaymentMethodParams data, [ Map<String, String> options = const {}, ]) async { final type = data.toJson()['type']; switch (type) { case 'Card': return createCardPaymentMethod(data, options); case 'Alipay': return createCardPaymentMethod(data, options); }

throw UnimplementedError();

}

The issue is that data.toJson()['type'];is null. . Running on VSCode, WIndows

flutter_stripe: ^3.0.2 flutter_stripe_web: ^1.0.2

glennarixxi avatar May 31 '22 12:05 glennarixxi

same issue here

Prayer-RecycleSmart avatar Jun 02 '22 02:06 Prayer-RecycleSmart

Additional information:

This method below expects to set type = data.toJson()['Type']

but data does not have 'Type', it has paymentMethodType

Please fix

data.toJson() Map (3 items) 0:"paymentMethodData" -> Map (2 items) 1:"options" -> null 2:"paymentMethodType" -> "Card"

@override Future<PaymentMethod> createPaymentMethod( PaymentMethodParams data, [ Map<String, String> options = const {}, ]) async { final type = data.toJson()['type']; switch (type) { case 'Card': return createCardPaymentMethod(data, options); case 'Alipay': return createCardPaymentMethod(data, options); }

throw UnimplementedError();

}

glennarixxi avatar Jun 07 '22 18:06 glennarixxi

any news on this? @glennarixxi did you find a solution?

Prayer-RecycleSmart avatar Jun 15 '22 04:06 Prayer-RecycleSmart

Unfortunately, I've not heard a thing - and have no solution to this. Surprised at the lack of response on something as important as this in Stripe Web

glennarixxi avatar Jun 15 '22 14:06 glennarixxi

We are at the moment figuring out a way of quickly syncing with web. To be very open me and @jonasbark are the only maintainers of this library and have our hands full with keeping mobile up to date. Bear in mind that Stripe mobile is a huge sdk . For web at the moment we recommend our checkout package .

We need a bit of time figuring out so we hope for your patience on this.

remonh87 avatar Jun 15 '22 19:06 remonh87

I will try the checkout package - I have started working on a direct integration but hopefully this will help with subscriptions as well. I would hope that Stripe can soon dedicate more resources to the web integration to address these kinds of bugs; I can readily see that it is a large workload for only 2 people. If you need any additional information on the bug, please let me know, i have provided what I believe should be helpful.

glennarixxi avatar Jun 15 '22 20:06 glennarixxi

Thank you @remonh87 for the effort you guys are putting to maintain this library. Can you create a payment method with the checkout package? I am passing the payment method id to my backend to future charges

final paymentMethod = await Stripe.instance
          .createPaymentMethod(const PaymentMethodParams.card());
await _userService.updateCreditCard(paymentMethod.id);

Prayer-RecycleSmart avatar Jun 17 '22 02:06 Prayer-RecycleSmart

@Prayer-RecycleSmart that should work

remonh87 avatar Jun 17 '22 08:06 remonh87

Sorry @remonh87 not sure what you mean.. My snippet is what it is not working in the new version of the web library (Flutter 3). My example is what is triggering the

UnimplementedError();

that @glennarixxi was mentioning in the issue. Is there any way we can create a paymentMethod with the checkout library? To me doesnt look like. Thanks

Prayer-RecycleSmart avatar Jun 17 '22 10:06 Prayer-RecycleSmart

Checkout does support adding payment methods to a Stripe customer: https://stripe.com/docs/payments/checkout

You can also look into having the user open up their customer portal using session: https://stripe.com/docs/api/checkout/sessions/create

jonasbark avatar Jun 22 '22 11:06 jonasbark

Any news about this issue ?

yacineblr avatar Jul 04 '22 09:07 yacineblr

I have been trying to find a solution with stripe_checkout but I am struggling. Seems like that the only way is to create a Session as @jonasbark was mentioning, but this can't be done just in the front end and if integrated with a backend that would require a very weird series of redirects. (see https://www.youtube.com/watch?v=S1WJuhGkY88)

The other solution would be to integrate open use checkout (https://stripe.com/docs/payments/save-and-reuse?platform=checkout) with the setup option, then setup a route into Flutter to get the CHECKOUT_SESSION_ID in the success url callback, and then call retrieve API to get maybe the payment method (maybe because from the api I could understand if its retuning a payment method aka pm_... as the previous version of the pub delivers)

Honestly I would be happy to use Checkout for web, I just haven't found a reliable way to do it.

Prayer-RecycleSmart avatar Jul 04 '22 11:07 Prayer-RecycleSmart

I am using the checkout method as suggested here: https://fidev.io/stripe-checkout-in-flutter-web/ which makes use of the JS package, but then the issue of reusing payment methods still exists.

Best solution is to fix the issue - namely fixing createPaymentMethod so that data.toJson()['Type'] is changed to data.toJson()['paymentMethodType '] which would then cause it to correctly return - seems like it should be a small fix.

glennarixxi avatar Jul 05 '22 19:07 glennarixxi

@glennarixxi have you been able to use to the JS integration as shown in the video to get the payment_method? that video is awesome but its just single checkout and it doesn't seems its returning any data back to the page once the transaction is completed.

We need to get the payment_method back in some way so we can attach it to the user.

Prayer-RecycleSmart avatar Jul 06 '22 00:07 Prayer-RecycleSmart

I retrieve the session_id from the Success URL. Then I retrieve the Session Object using the session_id which has the payment data - payment_intent. See https://stripe.com/docs/api/checkout/sessions/object. A lot of work for what should be readily available if the web elements worked. Not sure why this is not at least classified as a bug and more importantly when its going to be resolved.

glennarixxi avatar Jul 07 '22 22:07 glennarixxi

@glennarixxi you need the session_id to call the checkout endpoint (or at least this is how the Stripe Doc says). I was trying to avoid having to deal again with another backend integration.

The video you suggested firm fivdev.io is super useful but out of date..

Prayer-RecycleSmart avatar Jul 11 '22 05:07 Prayer-RecycleSmart

Session ID is optionally sent along in the Success URL, I grab it from there: https://yourdomain/#/checkoutSuccess?session_id={CHECKOUT_SESSION_ID}';

glennarixxi avatar Jul 13 '22 20:07 glennarixxi

Latest update has the same issue - on createPaymentMethod method in Class WebStripe , line: final type = data.toJson()['type'] is null. That is because this is the result of data.toJson()['type'] where 'type' does not exist - either change the line to data.toJson()['paymentMethodType'] or change the underlying data from paymentMethodType to type.

see results of data.toJson() below:

Map (3 items) 0: "paymentMethodData" -> Map (2 items) 1: "options" -> null 2: "paymentMethodType" -> "Card"

glennarixxi avatar Jul 23 '22 20:07 glennarixxi

Below are sections as an example of the website code: On the link, you pass this:  const webhostSuccess = 'https://xxxx.yyy/#/checkoutSuccess?session_id={CHECKOUT_SESSION_ID}'; …  const apiKey = stripeTestKey;   final stripe = Stripe(apiKey);  stripe.redirectToCheckout(CheckoutOptions(    lineItems: [      LineItem(price: priceId, quantity: 1),    ],    mode: 'subscription',    successUrl: Uri.base.host == 'localhost' ? localhostSuccess : webhostSuccess,    cancelUrl: Uri.base.host == 'localhost' ? localhostCancel : webhostCancel,  )); …Here is the route I use:   static Route _checkStripeRoute(String? name, String sessionId) {    if ((name ?? '').contains('checkoutSuccess')) {      return MaterialPageRoute(          settings: RouteSettings(name: Routes.checkoutSuccess),          builder: (context) => CheckoutSuccess(sessionId: sessionId));    } else      return _errorRoute();  }  Then the CheckoutSuccess page: class CheckoutSuccess extends StatelessWidget {  final String sessionId;   CheckoutSuccess({this.sessionId = ''});  Which then gets my session information by calling this:   Future callGetSession({    required String sessionId,  }) async {    try {      final url = Uri.parse('https://api.stripe.com/v1/checkout/sessions/$sessionId');      final response = await http.get(        url,        headers: {'Content-Type': 'application/json', HttpHeaders.authorizationHeader: 'Bearer $stripeTestSecretKey'},      );      var decoded = jsonDecode(response.body);      var data = StripeSession.fromJson(decoded);      return data;    } catch (e) {      print(e);      rethrow;    }  } (more data there, this is some of ***@***.***()class StripeSession extends ChangeNotifier {  String sessionId = '';  String payment_intent = '';  String subscription = '';  StripeSession();   factory StripeSession.fromJson(Map json) => _$SessionFromJson(json);   Map toJson() => _$SessionToJson(this);   }}  I hope this helps From: Jonas SmithSent: Tuesday, August 23, 2022 1:48 PMTo: flutter-stripe/flutter_stripeCc: glennarixxi; MentionSubject: Re: [flutter-stripe/flutter_stripe] Flutter Web Stripe.instance.createPaymentMethod Issue (Issue #760) I retrieve the session_id from the Success URL. Then I retrieve the Session Object using the session_id which has the payment data - payment_intent. See https://stripe.com/docs/api/checkout/sessions/object. A lot of work for what should be readily available if the web elements worked. Not sure why this is not at least classified as a bug and more importantly when its going to be resolved.I am confused on how you are able to retrieve the session_id in the first place do you have an example of this?—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you were mentioned.Message ID: ***@***.***> 

glennarixxi avatar Aug 25 '22 19:08 glennarixxi

In my case, this solved the problem https://github.com/flutter-stripe/flutter_stripe/pull/836

artebiakin avatar Sep 27 '22 07:09 artebiakin

I created a PR with a solution to this problem using version 5.1.0. https://github.com/flutter-stripe/flutter_stripe/pull/947

For now, you can use the following solution.

dependencies:
  flutter_stripe: ^5.1.0
  flutter_stripe_web: ^1.3.0

dependency_overrides:
  flutter_stripe_web:
    git:
      url: [email protected]:artebiakin/flutter_stripe-1.git
      path: packages/stripe_web 

Or download stripe_web package from repo: https://github.com/artebiakin/flutter_stripe-1 And add to your project

dependency_overrides:
  flutter_stripe_web:
    path: ../packages/stripe_web #your path

artebiakin avatar Sep 27 '22 09:09 artebiakin

I have the same problem. Any news about this issue ?

ayoubeslr avatar Oct 26 '22 18:10 ayoubeslr

I am also getting the same problem with the web app. I tried adding "flutter_stripe-1.git"

dependency_overrides:
  flutter_stripe_web:
    git:
      url: https://github.com/artebiakin/flutter_stripe-1.git
      path: packages/stripe_web

With this dependency when I am trying to create a payment method at that time it will return a null value with "last4" with "card" object.

This is the method for creating a payment method :

PaymentMethod? paymentMethod = await Stripe.instance.createPaymentMethod(PaymentMethodParams.card(
	paymentMethodData: PaymentMethodData(billingDetails: billingDetails),
));

Response in a web browser :

"Card": {
    "brand": "visa",
    "country": "US",
    "expYear": 2024,
    "expMonth": 4,
    "funding": "credit",
    "last4": null
}

Value of "last4" is require for setup intent.

punitsamcom84 avatar Nov 08 '22 05:11 punitsamcom84

This is now implemented in the new flutter_stripe_web: 2.1.0. Please open a new issue a new bug appears when using the method

jamesblasco avatar Dec 10 '22 19:12 jamesblasco