简体   繁体   English

PaymentIntent 需要一种支付方式——React,Django Rest

[英]The PaymentIntent requires a payment method — React, Django Rest

I have a React app and a Django Rest API.我有一个 React 应用程序和一个 Django Rest API。

My goal is to get the PaymentRequestButtonElement working.我的目标是让 PaymentRequestButtonElement 正常工作。

In my Stripe dashboard (test mode) I get the following logs:在我的 Stripe 仪表板(测试模式)中,我得到以下日志:

200 OK
POST    
/v1/payment_intents
12:22:55 PM

200 OK
POST    
/v1/payment_methods
12:22:54 PM

200 OK
POST    
/v1/tokens
12:22:53 PM

But in the Payments tab, I get the following:但是在“付款”选项卡中,我得到以下信息:

The PaymentIntent requires a payment method

Here is my React component:这是我的 React 组件:

import React, { useState, useEffect } from 'react';
// import { useNavigate } from 'react-router-dom';
// import { useShoppingCart } from 'use-shopping-cart';


import {
  PaymentRequestButtonElement,
  useStripe,
} from '@stripe/react-stripe-js';

const PaymentRequest = () => {
  // const history = useNavigate();
  // const { totalPrice, cartDetails, cartCount } = useShoppingCart();
  const stripe = useStripe();
  const [paymentRequest, setPaymentRequest] = useState(null);
  const price = 350;

  const handleButtonClicked = (event) => {
    // if (!cartCount) {
    //   event.preventDefault();
    //   alert('Cart is empty!');
    //   return;
    // }
    paymentRequest.on('paymentmethod', handlePaymentMethodReceived);
    paymentRequest.on('cancel', () => {
      paymentRequest.off('paymentmethod');
    });
    return;
  };

  const handlePaymentMethodReceived = async (event) => {
    // Send the cart details and payment details to our function.
    const paymentDetails = {
      payment_method: event.paymentMethod.id,
      shipping: {
        name: event.shippingAddress.recipient,
        phone: event.shippingAddress.phone,
        address: {
          line1: event.shippingAddress.addressLine[0],
          city: event.shippingAddress.city,
          postal_code: event.shippingAddress.postalCode,
          state: event.shippingAddress.region,
          country: event.shippingAddress.country,
        },
      },
    };
    const response = await fetch('https://my-api/create-payment-intent/', {
      method: 'post',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ 
        // cartDetails, 
        paymentDetails,
        amount: price,
        currency: 'usd',
        payment_method: 'card' 
        // automatic_payment_methods: true,
      }),
    }).then((res) => {
      return res.json();
    });
    if (response.error) {
      // Report to the browser that the payment failed.
      console.log(response.error);
      event.complete('fail');
    } else {
      // Report to the browser that the confirmation was successful, prompting
      // it to close the browser payment method collection interface.
      event.complete('success');
      // Let Stripe.js handle the rest of the payment flow, including 3D Secure if needed.
      const { error, paymentIntent } = await stripe.confirmCardPayment(
        response.paymentIntent.client_secret
      );
      if (error) {
        console.log(error);
        return;
      }
      if (paymentIntent.status === 'succeeded') {
        console.log('Payment succeeded!');
      } else {
        console.warn(
          `Unexpected status: ${paymentIntent.status} for ${paymentIntent}`
        );
      }
    }
  };

  useEffect(() => {
    if (stripe && paymentRequest === null) {
      const pr = stripe.paymentRequest({
        country: 'US',
        currency: 'usd',
        total: {
          label: 'Demo total',
          // 
          amount: price,
          pending: true,
        },
        requestPayerName: true,
        requestPayerEmail: true,
        requestShipping: true,
        shippingOptions: [
          {
            id: 'standard-global',
            label: 'Global shipping',
            detail: 'Handling and delivery fee',
            amount: 350,
          },
        ],
      });
      // Check the availability of the Payment Request API first.
      pr.canMakePayment().then((result) => {
        if (result) {
          setPaymentRequest(pr);
        }
      });
    }
  }, [stripe, 
      paymentRequest, 
      // totalPrice
    ]);

  useEffect(() => {
    if (paymentRequest) {
      paymentRequest.update({
        total: {
          label: 'Demo total',
          amount: 350,
          pending: false,
        },
      });
    }
  }, [
      // totalPrice, 
      paymentRequest
    ]);

  if (paymentRequest) {
    return (
      <div className="payment-request-button">
        <PaymentRequestButtonElement
          options={{ paymentRequest }}
          onClick={handleButtonClicked}
        />
        --- OR ---
      </div>
    );
  }

  return '';
};

export default PaymentRequest;

and here is my Django REST View这是我的 Django REST 查看

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've tried variations of passing automatic_payments as true and passing the payment_method as 'card', no joy我已经尝试过将 automatic_payments 作为 true 传递并将 payment_method 作为“卡”传递的变体,没有快乐

There's a couple of options that you can do in order to fix the problem here.您可以执行几个选项来解决此处的问题。

Option 1: Pass the PM in the backend方案一:在后台传递PM

When you call fetch on https://my-api/create-payment-intent/ you are passing the paymentDetails that you're not using in your stripe.PaymentIntent.create method.当您在 https://my-api/create-payment-intent/ 上调用 fetch 时,您将传递未在paymentDetails方法中使用的stripe.PaymentIntent.create For this to work, you need to first deserialize your request to get access to this information since it's nested (eg this guide ).为此,您需要首先反序列化您的请求以访问此信息,因为它是嵌套的(例如本指南)。 Then you need to pass payment_method to the stripe.PaymentIntent.create method.然后你需要将payment_method传递给stripe.PaymentIntent.create方法。 In this option you don't have to change anything in your frontend code.在此选项中,您不必更改前端代码中的任何内容。

Option 2: Pass the PM in the frontend选项 2:在前端传递 PM

When you call stripe.confirmCardPayment you can pass in the payment_method as explained here .当您调用stripe.confirmCardPayment时,您可以按照此处的说明传入 payment_method。 In this option you don't have to change anything in your backend code but you can remove the paymentDetails from the request to your backend.在此选项中,您不必更改后端代码中的任何内容,但您可以从请求中删除对后端的paymentDetails信息。

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

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