简体   繁体   English

付款成功消息不会从 Stripe 发送到 React 应用程序

[英]Payment success message doesn’t make it to from Stripe to React app

I have a React app which I am testing on Vercel.我有一个正在 Vercel 上测试的 React 应用程序。

The app was created using create-react-app.该应用程序是使用 create-react-app 创建的。

I have a Stripe Account and a Django REST API, hosted on Heroku.我有一个 Stripe 帐户和一个 Django REST API,托管在 Heroku。

I'm using PaymentRequestButtonElement to generate a dynamic Apple / Google Pay button.我正在使用PaymentRequestButtonElement生成一个动态的 Apple / Google Pay 按钮。

I'm testing Google Pay via chrome with my personal card details saved into the browser.我正在通过 chrome 测试 Google Pay,并将我的个人卡详细信息保存到浏览器中。

The price is fetched from my django app, each product is a 'Card', within which the payment button appears, with the price of that product passed in.价格是从我的 django 应用程序中获取的,每个产品都是一张“卡”,其中显示付款按钮,并传入该产品的价格。

The payments go through just fine and the payment shows up in my Stripe dashboard as successful.付款 go 一切顺利,付款在我的 Stripe 仪表板中显示为成功。

My /create-payment-intent/ seems functional as the payment goes through and that it generates a client secret when I test it in Postman.我的 /create-payment-intent/ 似乎在付款过程中起作用,并且当我在 Postman 中对其进行测试时,它会生成一个客户端密码。

The issue is simply that the React app doesn't seem to be listening for the payment success or failure, as it doesn't say so on the browser console or on the UI.问题很简单,React 应用程序似乎没有监听支付成功或失败,因为它没有在浏览器控制台或 UI 上这样说。

The google pay sheet times out and the following is printed to the console:谷歌支付表超时,以下内容打印到控制台:

DEVELOPER_ERROR in loadPaymentData: An error occurred in call back, please try to avoid this by setting structured error in callback response H @ pay.js:149

Here is my React component.这是我的 React 组件。

CheckoutForm.js CheckoutForm.js

import React, { useEffect, useState } from 'react';
import {
  PaymentRequestButtonElement,
  useStripe,
} from '@stripe/react-stripe-js';
import axios from 'axios';

const CheckoutForm = (props) => {
  const stripe = useStripe();
  const [paymentRequest, setPaymentRequest] = useState(null);
  const [paymentSuccess, setPaymentSuccess] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);
  const [successMessage, setSuccessMessage] = useState(null);
  // const price = props.price;
  // const dollar_price = price * 100;

  useEffect(() => {
    if (stripe) {
      const pr = stripe.paymentRequest({
        country: 'US',
        currency: 'usd',
        total: {
          label: 'Purchase',
          amount: 100,
        },
        requestPayerName: true,
        requestPayerEmail: true,
        applePay: true,
        googlePay: true,
      });

      pr.canMakePayment().then(result => {
        if (result) {
          setPaymentRequest(pr);
        }
      });
    }
  }, [stripe]);

  useEffect(() => {
    if (paymentRequest) {
      paymentRequest.on('paymentmethod', async event => {
        const paymentMethod = event.paymentMethod;
        try {
          const response = await axios.post(
            'https://my-api.com/create-payment-intent/',
            {
              paymentMethodId: paymentMethod.id,
              amount: 100,
              automatic_payment_methods: {
                'enabled': true,
              },
              currency: 'usd',
            }
          );

          const pi = await stripe.confirmCardPayment(response.data.client_secret, {
            payment_method: paymentMethod.id
          });
          
          if (pi.status === 'succeeded') {
            event.complete();
            console.log('Payment succeeded!');
            setPaymentSuccess(true);
            setErrorMessage(null);
            setSuccessMessage("Payment succeeded!");
          } else if (pi.status === 'requires_action' || pi.status === 'requires_confirmation') {
            event.complete('success');
            console.log('Additional steps required!');
            setErrorMessage(null);
            setSuccessMessage("Additional steps required, please check your email for further instructions.");
            // Prompt user to complete additional steps
          } else if (pi.status === 'requires_payment_method') {
            event.complete('fail');
            console.log('Payment method required!');
            setErrorMessage("Payment method required. Please add a new payment method.");
            // Prompt user to add a new payment method
          } else if (pi.status === 'processing') {
            event.complete('success');
            console.log('Payment is being processed!');
            setErrorMessage(null);
            setSuccessMessage("Payment is being processed. Please wait.");
            // Show a message to the user that the payment is being processed
          } else if (pi.status === 'canceled') {
            event.complete('fail');
            console.log('Payment canceled!');
            setErrorMessage("Payment canceled.");
            // Show a message to the user that the payment was canceled
          } else if (pi.status === 'failed') {
            event.complete('fail');
            console.log('Payment failed!');
            setErrorMessage("Payment failed. Please check your information and try again.");
            // Show a message to the user that the payment failed
          }
        } catch (error) {
          event.complete('fail');
          console.log('An error occurred:', error);
          setErrorMessage("An error occurred. Please try again later.");
          // Show an error message to the user
        }
      });
    }
  }, [paymentRequest, stripe]);



  if (paymentRequest) {
    return <>
    {paymentSuccess && <p>Payment Successful!</p>}
    <PaymentRequestButtonElement options={{ paymentRequest }} />
  </>
  }

  return 'Insert your form or button component here.';
};

export default CheckoutForm;

Here is my index.js这是我的 index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {Elements} from '@stripe/react-stripe-js';
import {loadStripe} from '@stripe/stripe-js';

import CheckoutForm from './CheckoutForm';

// Make sure to call `loadStripe` outside of a component's render to avoid
// recreating the `Stripe` object on every render.
const stripePromise = loadStripe('pk_live_123');

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
   <Elements stripe={stripePromise}>
      <CheckoutForm />
    </Elements>
  </React.StrictMode>
);

reportWebVitals();

And here is my django view这是我的 django 视图

class PaymentIntentView(APIView):
    def post(self, request, *args, **kwargs):
        amount = request.data.get('amount')
        currency = request.data.get('currency')
        automatic_payment_methods = request.data.get('automatic_payment_methods')

        try:
            intent = stripe.PaymentIntent.create(
                amount=amount,
                currency=currency,
                automatic_payment_methods={
                    'enabled': True,
                },
                # You can also add other options like capture_method, setup_future_usage, etc.
            )

            return Response({'client_secret': intent.client_secret, 'id': intent.id})
        except Exception as e:
            return Response({'error': str(e)})

I feel like I'm missing a step here.我觉得我在这里错过了一步。

Happy to share more info if necessary.如有必要,很乐意分享更多信息。

I'm expecting the console and the UI to produce a success or failure message, but it just times out.我期待控制台和 UI 产生成功或失败消息,但它只是超时。 The payment appears as successful in my Stripe Dashboard.付款在我的 Stripe 控制面板中显示为成功。

Inside the function paymentRequest.on('paymentmethod'... you have the call to your endpoint "https://my-api.com/create-payment-intent/" then a subsequent JS call to const pi = await stripe.confirmCardPayment .在 function paymentRequest.on('paymentmethod'...中,您调用了端点“https://my-api.com/create-payment-intent/”,然后是对const pi = await stripe.confirmCardPayment

From what you described, it looks like some bits are off around this area.根据您的描述,该区域周围似乎有些地方不对劲。 You can put breakpoints on the endpoint call and the confirmCardPayment to see if they really go through.您可以在端点调用和 confirmCardPayment 上放置断点,以查看它们是否真的 go 通过。 You can also open your browser console to see whether the real ajax call succeeded (instead of testing in Postman).你也可以打开你的浏览器控制台,看看真正的 ajax 调用是否成功(而不是在 Postman 中测试)。

If they are succeeded, what is the pi.status on your console.log?如果他们成功了,你的 console.log 上的pi.status是什么?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM