Stripe 错误:客户尚未在 flutter 中输入他们的支付方式

Stripe error the customer has not entered their payment method in flutter

提问人:Subhangi Pawar 提问时间:10/28/2021 更新时间:6/24/2023 访问量:6625

问:

我使用 Firebase CLI 在我的 flutter 应用程序中集成了 flutter_stripe 2.0.1 插件。从 firebase 提供的 URL 获取 paymentIntent 的成功响应。但在 Stripe 管理平台中,付款状态为“未完成”。

下面是我的 node.js 代码索引 .js 文件

const functions = require('firebase-functions');
const stripe = require('stripe')(functions.config().stripe.testkey);

exports.stripePayment = functions.https.onRequest(async (req, res) => {  
    const paymentIntent = await stripe.paymentIntents.create({
        amount: 1,
        currency: 'usd'
    },
        function(err, paymentIntent) {
            if(err != null){
                console.log(err);
            } else {
                res.json({
                    paymentIntent: paymentIntent.client_secret,
                })
            }
        }
    )

});

下面是我的 flutter 代码

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Stripe.publishableKey = stripePublishableKey;
  Stripe.merchantIdentifier = 'merchant.flutter.stripe.test'; //any string works
  await Stripe.instance.applySettings();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
      return MaterialApp(
        home: DashboradPage(),
      );
  }
}

class DashboradPage extends StatefulWidget {
  const DashboradPage({Key? key}) : super(key: key);

  @override
  _DashboradPageState createState() => _DashboradPageState();
}

class _DashboradPageState extends State<DashboradPage> {
  Map<String, dynamic>? paymentIntentData;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Stripe Examples'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            makePayment();
          },
          child: Text('Pay Amount'),
        ),
      ),
    );
  }

  Future<void> makePayment() async {
    final url = Uri.parse(
        'https://us-central1-stripeflutterdemo.cloudfunctions.net/stripePayment');

    final header = {'Content-Type': 'application/json'};
    try {
      final response = await http.get(url, headers: header);
      paymentIntentData = json.decode(response.body);
      await Stripe.instance.initPaymentSheet(
            paymentSheetParameters: SetupPaymentSheetParameters(
          paymentIntentClientSecret: paymentIntentData?['paymentIntent'] ?? '',
          applePay: true,
          googlePay: true,
          style: ThemeMode.light,
          merchantCountryCode: 'US',
          merchantDisplayName: 'Flutter Stripe Store Demo',
        ));
        setState(() {});
       displayPaymentSheet();
    } catch (e) {
      print(e);
      displaySnackbar(e.toString());
    }
  }

  Future<void> displayPaymentSheet() async {
    try {
      await Stripe.instance.presentPaymentSheet();
      // await Stripe.instance.presentPaymentSheet(
      //   parameters: PresentPaymentSheetParameters(
      //     clientSecret: paymentIntentData?['paymentIntent'] ?? '',
      //     confirmPayment: true,
      //   ),
      // );

      setState(() {
        paymentIntentData = null;
      });
      displaySnackbar('Payment succesfully completed');
    } catch (e) {
      print(e);
      displaySnackbar(e.toString());
    }
  }

  void displaySnackbar(String msg) {
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(
        content: Text(msg),
      ),
    );
  }
}

以下是 makePayment() 中提到的 URL 的邮递员响应

enter image description here

我使用了付款表,当我点击“付款”按钮时,它重定向到 webview(身份验证已完成),但在 Stripe 管理平台中,付款状态为“未完成”。

Stripe 管理平台支付事件数据 PaymentIntent 状态:requires_payment_method, PaymentIntent 状态:requires_action

From Stripe
payment_intent.payment_failed
View event detail
Event data
{
  "id": "pi_3JpZh7SIKwX0CSUQ0sUoM9wK",
  "object": "payment_intent",
  "last_payment_error": {
    "message": "As per Indian regulations, export transactions require a description. More info here: https://stripe.com/docs/india-exports",
    "param": "description",
    "payment_method": {
      "id": "pm_1JpZijSIKwX0CSUQ7u91wths",
      "object": "payment_method",
      "billing_details": {
        "address": {
          "city": null,
          "country": "US",
          "line1": null,
          "line2": null,
          "postal_code": "45612",
          "state": null
        },
        "email": null,
        "name": null,
        "phone": null
      },
      "card": {
        "brand": "visa",
        "checks": {
          "address_line1_check": null,
          "address_postal_code_check": "unchecked",
          "cvc_check": "unchecked"
        },
        "country": "US",
        "exp_month": 4,
        "exp_year": 2044,
        "fingerprint": "EK9VAoccqqCLBqQk",
        "funding": "credit",
        "generated_from": null,
        "last4": "4242",
        "networks": {
          "available": [
            "visa"
          ],
          "preferred": null
        },
        "three_d_secure_usage": {
          "supported": true
        },
        "wallet": null
      },
      "created": 1635431806,
      "customer": null,
      "livemode": false,
      "metadata": {
      },
      "type": "card"
    },
    "type": "invalid_request_error"
  },
  "livemode": false,
  "next_action": null,
  "status": "requires_payment_method",
  "amount": 1,
  "amount_capturable": 0,
  "amount_received": 0,
  "application": null,
  "application_fee_amount": null,
  "canceled_at": null,
  "cancellation_reason": null,
  "capture_method": "automatic",
  "charges": {
    "object": "list",
    "data": [
    ],
    "has_more": false,
    "total_count": 0,
    "url": "/v1/charges?payment_intent=pi_3JpZh7SIKwX0CSUQ0sUoM9wK"
  },
  "client_secret": "pi_3JpZh7SIKwX0CSUQ0sUoM9wK_secret_oVhK5CmrcHjImvFMyoo51GCXy",
  "confirmation_method": "automatic",
  "created": 1635431705,
  "currency": "usd",
  "customer": null,
  "description": null,
  "invoice": null,
  "metadata": {
  },
  "on_behalf_of": null,
  "payment_method": null,
  "payment_method_options": {
    "card": {
      "installments": null,
      "network": null,
      "request_three_d_secure": "automatic"
    }
  },
  "payment_method_types": [
    "card"
  ],
  "receipt_email": null,
  "review": null,
  "setup_future_usage": "off_session",
  "shipping": null,
  "source": null,
  "statement_descriptor": null,
  "statement_descriptor_suffix": null,
  "transfer_data": null,
  "transfer_group": null
}

以下是iPhone截图

enter image description here

enter image description here

enter image description here

flutter google-cloud-functions 条带支付

评论


答:

0赞 ErnestoC 10/29/2021 #1

根据 Stripe 文档,该消息表示您尚未将付款方式附加到您的付款意图中:required_payment_methodstatus

创建 PaymentIntent 后,在附加付款方式之前,它的状态为 requires_payment_method。

有一份官方文档解释了如何将 Stripe 支付与您的 Firebase 后端集成。它提供了使用 Stripe 正确设置付款所需的所有代码和步骤。在文件内的示例代码中,它们在创建付款意向时包含其他对象index.jsstripe.paymentIntents.create()

const payment = await stripe.paymentIntents.create(
    {
      amount,
      currency,
      customer,
      Payment_method, //payment method when creating the payment intent
      off_session: false,
      confirm: true,
      confirmation_method: 'manual',
    },
    { idempotencyKey }
  );

由于您的示例缺少付款方式,因此它可以解释您收到的错误,因为创建时没有付款方式。我建议按照指南来涵盖所有必需的步骤,以避免可能出现的进一步错误。您还可以查看完整的示例代码,该代码已记录在案,可以针对您的用例和库进行自定义。PaymentIntentflutter_stripe

评论

1赞 Subhangi Pawar 10/29/2021
感谢您的详细解答。但是如果我对 index.js 文件进行任何更改,它会抛出错误 408。您能告诉我上面代码中的更改吗,尽管它是一个演示应用程序,我们将集成到我们的项目中。
0赞 ErnestoC 10/30/2021
408 错误表示请求缺少必需的参数。有一个相关的问题,其中必需的参数在使用 Stripe 支付的 Flutter 应用程序中显示此错误。您可以查看文档,因为有一个示例应用程序可以帮助您制定正确的请求。flutter_stripe
3赞 Jeremie Houet 3/9/2023 #2

我正在使用flutter_stripe包,遇到了完全相同的问题。在应用程序日志中取得了成功,但在 Stripe 日志中,付款未完成,因为未添加付款方式。关于这个问题已经找了一段时间了,我通过添加如下后缀来修复它:Stripe.instance.confirmPaymentSheetPayment();await Stripe.instance.presentPaymentSheet()

 await Stripe.instance.presentPaymentSheet().then((e) {
      Stripe.instance.confirmPaymentSheetPayment();
    });

我发现他们的文档非常令人困惑,尤其是 Stripe 服务器端。

希望对您有所帮助!

评论

0赞 saintjab 3/21/2023
非常有帮助,我在这次:(上浪费了大约三个小时谢谢伙计
1赞 Inderjit Shahi 6/24/2023 #3

在您的货币代码中,请确保与您的 Stripe 账户中的代码相同。我通过这样做解决了这个问题

paymentIntent = await createPaymentIntent('10', 'INR');