如何将Django React App与Stripe Payment集成

介绍 (Introduction)

Have you ever wanted to create an app in which the users would have to pay a few one-time fees and have a periodic subscription as well? On the one hand, you’d like to keep as much information as needed to have control over your customers and their payments. On the other hand, credit cards data are really sensitive, and storing them in your database would be very risky.

您是否曾经想过创建一个应用程序,用户必须在其中支付一些一次性费用并定期订阅? 一方面,您希望保留尽可能多的信息,以控制您的客户及其付款。 另一方面,信用卡数据确实很敏感,将其存储在数据库中会带来很大的风险。

Fortunately, there’s a very interesting solution. Integrating your app with Stripe will save you time and provide a really clean and safe payment process. With its extensive API, you’ll be able to implement any type of money transaction you can imagine, and, moreover, all sensitive data will be secure in the Stripe cloud.

幸运的是,有一个非常有趣的解决方案。 将您的应用程序与Stripe集成在一起可以节省您的时间,并提供真正干净安全的付款流程。 凭借其广泛的API,您将能够实现您可以想象的任何类型的货币交易,而且,所有敏感数据都将在Stripe云中安全保存。

我们的目标 (Our Goal)

For the purpose of this article, we’ll create a simple app using the Django REST framework for our API back end and React for the front-end side.

就本文而言,我们将使用Django REST框架(用于API后端)和React(用于前端)创建一个简单的应用程序。

我们的应用程序的主要流程 (Main flow of our app)

  1. The user provides his email and credit/debit card data.

    用户提供他的电子邮件和信用卡/借记卡数据。
  2. We create a new Stripe customer based on the data the user provided.

    我们根据用户提供的数据创建一个新的Stripe客户。
  3. The user will be charged with a one-time fee for creating an account.

    将向用户收取创建帐户的一次性费用。
  4. The user will also be signed up for the monthly subscription to keep his account active.

    用户还将注册每月订阅,以保持其帐户处于活动状态。

Seems quite simple, doesn’t it? So let’s start!

看起来很简单,不是吗? 因此,让我们开始吧!

设置Django API (Set Up the Django API)

Assume we’ve already created a Django project called StripeApp with the Django REST framework library installed.

假设我们已经创建了一个安装了Django REST框架库的Django项目,名为StripeApp

让我们在 StripeApp 项目根目录中 创建一个新应用 (Let’s create a new app in our StripeAppproject root)

python manage.py startapp payments

Our project structure should look like that (make sure you have the files with bolded names, and create missing ones, if needed):

我们的项目结构应如下所示(确保您的文件具有加粗名称,并在需要时创建丢失的文件):

- StripeApp/
- payments
- migrations/
- __init.py__
- admin.py
- apps.py
- models.py
- tests.py
- urls.py
- views.py
- stripeapp/
- __init.py__- settings.py
- urls.py

安装Stripe库 (Install the Stripe library)

pip install --upgrade stripe

登录Stripe仪表板,并获取测试密钥 (Sign up to the Stripe dashboard, and get your test keys)

Create your Stripe account and get your test keys (publishable and secret) from the dashboard.

创建您的Stripe帐户 ,并从信息中心获取测试密钥(可发布和秘密)。

Stripe API Keys
Stripe dashboard: API keys
条纹仪表板:API密钥

将您的密钥复制到Django项目 (Copy your secret key to your Django project)

# payments/views.pystripe.api_key = ‘sk_test_’ # your real key will be much longer

向Stripe API发出测试请求 (Make a test request to the Stripe API)

Create a simple view making a Stripe payment to check if your key is valid.

创建一个简单的视图以进行Stripe付款以检查您的密钥是否有效。

Note: Right now, just copy the code and don’t try to understand what’s going on in this function. Everything will be explained a bit later.

注意:现在,只需复制代码即可,不要试图了解此函数的功能。 一切将在稍后解释。

# payments/views.py@api_view(['POST'])
def test_payment(request):test_payment_intent = stripe.PaymentIntent.create(amount=1000, currency='pln', payment_method_types=['card'],receipt_email='test@example.com')return Response(status=status.HTTP_200_OK, data=test_payment_intent)

Connect the view with the URL in payments/urls.py.

payments/urls.py的URL连接视图。

# payments/urls.pyfrom django.conf.urls import url
from payments import viewsurlpatterns = [
url(r'^test-payment/$', views.test_payment),
]

And define the payments URL prefix in stripeapp/urls.py.

并在stripeapp/urls.py定义payments URL前缀。

# stripeapp/urls.pyurlpatterns = [
path('admin/', admin.site.urls), # add this line path('payments/', include('payments.urls'))
]

Send your new request (http://localhost:8000/payments/test-payment) using Postman. If you get a JSON object similar to the one below, it means you’ve just successfully sent your first request to Stripe.

使用Postman发送新请求( http://localhost:8000/payments/test-payment )。 如果您获得与以下对象类似的JSON对象,则意味着您已成功向Stripe发送了第一个请求。

{ 
"id": "pi_123", #you will have a unique id every time
"object": "payment_intent",
"amount": 1000,
"amount_capturable": 0,
"amount_received": 0,
"application": null,
"application_fee_amount": null,
...
}

设置前端项目 (Set Up the Front-End Project)

Assume we’ve already created a React project called StripeAppFront.

假设我们已经创建了一个名为StripeAppFront的React项目。

安装React Stripe (Install React Stripe)

npm install @stripe/react-stripe-js @stripe/stripe-js

创建结帐表格 (Create the checkout form)

Create a new React component that’ll display a form like this:

创建一个新的React组件,它将显示如下形式:

CheckoutForm

We want the user to provide his email and credit/debit card data. Although an email will be sent to our API, the card’s sensitive data will be processed by Stripe’s CardElement so we don’t store them anywhere insecurely. According to the Stripe documentation:

我们希望用户提供他的电子邮件和信用卡/借记卡数据。 尽管将向我们的API发送电子邮件,但是Stripe的CardElement将处理卡的敏感数据,因此我们不会将它们存储在不安全的地方。 根据Stripe 文档

“Stripe Elements make collecting payment details more secure and help prevent malicious actors from stealing any sensitive information. We generate a secure iframe and isolate sensitive information from your site — eliminating entire classes of attacks — while still giving you full visual control.”

“条带元素使收集付款细节更加安全,并有助于防止恶意行为者窃取任何敏感信息。 我们会生成安全的iframe,并从您的网站中隔离敏感信息,从而消除了所有类型的攻击,同时仍为您提供了完全的视觉控制。”

So let’s write some code:

因此,让我们编写一些代码:

In App.js, load you Stripe’s publishable bey and import Elements.

App.js ,加载Stripe可发布的bey并导入Elements

// App.js
import React from 'react';
import './App.css';
import {Elements} from '@stripe/react-stripe-js';
import {loadStripe} from "@stripe/stripe-js/pure";
import CheckoutForm from "./components/CheckoutForm";
const stripePromise = loadStripe('pk_test_');const App = () => (
<Elements stripe={stripePromise}>
<CheckoutForm />
</Elements>
);
export default App;

Create a new folder called components, and inside it, create the file CheckoutForm.js. It’ll be the most important component in the front-end project.

创建一个名为components的新文件夹,并在其中创建文件CheckoutForm.js 。 这将是前端项目中最重要的组件。

# components/CheckoutForm.jsimport {CardElement, useElements, useStripe} from "@stripe/react-stripe-js";
import React, {useState} from "react";
import ApiService from "../api";const CheckoutForm = () => {
const [error, setError] = useState(null);
const [email, setEmail] = useState('');
const stripe = useStripe();
const elements = useElements();// Handle real-time validation errors from the CardElement.const handleChange = (event) => {
if (event.error) {
setError(event.error.message);
} else {
setError(null);
}
}// Handle form submission.const handleSubmit = async (event) => {event.preventDefault();
};
return (
<form onSubmit={handleSubmit} className="stripe-form">
<div className="form-row">
<label htmlFor="email">Email Address</label>
<input className="form-input" id="email" name="name" type="email" placeholder="jenny.rosen@example.com" required
value={email} onChange={(event) => { setEmail(event.target.value)}} />
</div>
<div className="form-row">
<label for="card-element">Credit or debit card</label>
<CardElement id="card-element" onChange={handleChange}/>
<div className="card-errors" role="alert">{error}</div>
</div>
<button type="submit" className="submit-btn">
Submit Payment
</button>
</form>
);
};export default CheckoutForm;

创建付款方式 (Create the payment method)

Next we’ll use the Stripe API to create the PaymentMethod object and send its ID to our API. Once again, let’s take a quick look at the Stripe documentation and check out the definition of PaymentMethod:

接下来,我们将使用Stripe API创建PaymentMethod对象并发送其ID 到我们的API。 再次让我们快速查看Stripe文档,并查看PaymentMethod的定义:

PaymentMethod objects represent your customer’s payment instruments. They can be used with PaymentIntents to collect payments or saved to Customer objects to store instrument details for future payments.”

PaymentMethod对象代表您客户的付款方式。 它们可以与PaymentIntents一起使用以收集付款,也可以将其保存到Customer对象以存储工具详细信息以备将来付款。”

This means that PaymentMethod stores the user’s card data to use in payments transactions.

这意味着PaymentMethod存储用户的卡数据以用于支付交易。

So let’s add a few lines to the handleSubmit method:

因此,让我们在handleSubmit方法中添加几行:

const handleSubmit = async (event) => {event.preventDefault();
const card = elements.getElement(CardElement);
// add these lines const {paymentMethod, error} = await stripe.createPaymentMethod({
type: 'card',
card: card
});

}

Note: You can check in the documentation to see the different types of PaymentMethod Stripe offers.

注意:您可以签入文档以查看不同类型PaymentMethod Stripe提供的内容。

We also added the console.log operation to check how the PaymentMethod object really looks like. So open your page (http://localhost:3000), and pass the test data to the form.

我们还添加了console.log操作,以检查PaymentMethod对象的真实外观。 因此,打开您的页面( http://localhost:3000 ),然后将测试数据传递给表单。

Note: As a card number, you can use one of the testing cards provided by Stripe, (e.g., 4242 4242 4242 4242). The CVC and ZIP code can both be any number, and the expiration date can be any future date.

注意:作为卡号,您可以使用Stripe提供的测试卡之一(例如4242 4242 4242 4242 )。 CVC和邮政编码都可以是任何数字,并且到期日期可以是任何将来的日期。

Hit the Submit Payment button, and take a look into the browser console. You can see an object containing quite a lot of data, but the most important thing is the card property (shown on the image below). We can see it isn’t storing the full card number, only the last four numbers. Now we’re sure nobody will be able to capture user’s card details.

点击“提交付款”按钮,然后浏览浏览器控制台。 您可以看到一个包含大量数据的对象,但最重要的是card属性(如下图所示)。 我们可以看到它并没有存储完整的卡号,只有最后四个数字。 现在,我们确定没有人能够捕获用户的卡详细信息。

PaymentMethod object
The PaymentMethod object
PaymentMethod对象

发送PaymentMethod.id到Django API (Send PaymentMethod.id to the Django API)

Install the axios package to handle sending requests on the front-end side.

安装axios软件包以处理前端的发送请求。

npm install axios --save

Then in the project root, create the file api.js, and create the ApiService class. Inside the newly created class, define the static method saveStripeInfo to send the POST request to our API (we’ll handle this request in a while):

然后在项目根目录中,创建文件api.js ,并创建ApiService类。 在新创建的类中,定义静态方法saveStripeInfo将POST请求发送到我们的API(我们将在一段时间内处理此请求):

// api.jsimport axios from "axios";
export const API_URL ='http://localhost:8000'export const api = axios.create({
baseURL: API_URL,
headers: {
"Content-type": "application/json"
}
});export default class ApiService{
static saveStripeInfo(data={}){
return api.post(`${API_URL}/payments/save-stripe-info/`, data)
}
}

Finally, call the method in the CheckoutForm component:

最后,在CheckoutForm组件中调用该方法:

// CheckoutForm.jsconst handleSubmit = async (event) => {[...]const {paymentMethod, error} = await stripe.createPaymentMethod({
type: 'card',
card: card
}); //add these lines ApiService.saveStripeInfo({
email, payment_method_id: paymentMethod.id})
.then(response => {
console.log(response.data);
}).catch(error => {
console.log(error)
})
};}

实施API请求与Stripe连接 (Implement the API Request Connecting With Stripe)

Now it’s time to create an API view that’ll reach our main goals. In this view, we’re going to create a new Stripe Customer and charge his card with a one-time fee (PaymentIntent). Then, we’ll set up his monthly subscription (Subscription). Before we start coding, let’s take a look at the Stripe documentation and read about the mentioned objects.

现在该创建一个可以实现我们主要目标的API视图了。 在这种情况下,我们将创建一个新的Stripe Customer并向其卡收取一次性费用( PaymentIntent )。 然后,我们将设置他的每月订阅( Subscription )。 在开始编码之前,让我们看一下Stripe文档并阅读所提到的对象。

Customer objects allow you to perform recurring charges, and to track multiple charges, that are associated with the same customer.”

Customer对象使您可以执行与同一客户相关的经常性费用并跟踪多个费用。”

“A PaymentIntent guides you through the process of collecting a payment from your customer. We recommend that you create exactly one PaymentIntent for each order or customer session in your system.”

PaymentIntent指导您完成从客户收取款项的过程。 我们建议您为系统中的每个订单或客户会话都完全创建一个PaymentIntent 。”

Subscriptions allow you to charge a customer on a recurring basis.”

“通过Subscriptions您可以重复向客户收费。”

OK, now we know much more, don’t we? So let’s code it.

好,现在我们知道更多了,不是吗? 因此,让我们对其进行编码。

创建您的客户 (Create your customer)

In payments/views.py, create the new method save_stripe_info. We’ll pass email and payment_method_id to Stripe so the user will be linked with the provided card data.

payments/views.py ,创建新方法save_stripe_info 。 我们会将emailpayment_method_id传递给Stripe,以便将用户与提供的卡数据链接。

def save_stripe_info(request):
data = request.data
email = data['email']
payment_method_id = data['payment_method_id']# creating customercustomer = stripe.Customer.create(email=email, payment_method=payment_method_id)
return Response(status=status.HTTP_200_OK, data={
'message': 'Success',
'data': {'customer_id': customer.id}
)

And add it to payments/urls.py:

并将其添加到payments/urls.py

urlpatterns = [
url(r'^test-payment/$', views.test_payment), url(r'^save-stripe-info/$', views.save_stripe_info),

Now you can refresh our webpage and test it. Open you browser console, fill the form with test@gmail.com, use any test card number, and submit it.

现在,您可以刷新我们的网页并进行测试。 打开浏览器控制台,用test@gmail.com填写表格,使用任何测试卡号,然后提交。

Image for post

In the console, you should see the Success status message along with the newly created customer ID.

在控制台中,您应该看到“ Success状态消息以及新创建的客户ID。

Image for post

Let’s check something else. Log into your Stripe dashboard, and open the Customers tab. Here, you can see a new customer with the email we provided in the form. If you click on it and open the customer details, you’ll see the same ID that was printed in the console.

让我们检查一下其他内容。 登录到Stripe仪表板,然后打开“ 客户”选项卡。 在这里,您可以通过表格中提供的电子邮件看到新客户。 如果单击它并打开客户详细信息,您将看到控制台中打印的相同ID。

Image for post
Customers list in the Stripe dashboard
客户在Stripe仪表板中列出
Image for post
Stripe dashboard: Customer details
条纹仪表板:客户详细信息

If you scroll down the customer-details page, you’ll find out that the payment-methods section contains the card data provided in the form.

如果向下滚动“客户详细信息”页面,则会发现“付款方法”部分包含表格中提供的卡数据。

Image for post
Stripe dashboard: Client payment methods
条形仪表板:客户付款方式

This means we’ve just created our first Stripe customer.

这意味着我们刚刚创建了第一个Stripe客户。

检查客户是否已经存在 (Check if the customer already exists)

OK, let’s slightly recap our app flow. The user is passing their email and credit card data, and based on that, we’re creating a new Stripe customer. In a moment, we’ll charge him, but what if the same person fills out the form for the second time? We definitely don’t want to have duplicated accounts in Stripe, so we need to validate if the provided email has already been used.

好的,让我们简要回顾一下我们的应用程序流程。 用户正在传递其电子邮件和信用卡数据,并在此基础上创建新的Stripe客户。 稍后,我们将向他收取费用,但是如果同一个人第二次填写该表格怎么办? 我们绝对不希望在Stripe中有重复的帐户,因此我们需要验证提供的电子邮件是否已被使用。

The Stripe API shares a method list that lists our customers. With an email parameter, we can fetch a filtered list and check if the email has been already linked to another customer. Let’s check it out:

Stripe API共享一个列出我们的客户的方法list 。 使用email参数,我们可以获取过滤的列表,并检查电子邮件是否已经链接到另一位客户。 让我们来看看:

# payments/views.py@api_view(['POST'])
def save_stripe_info(request):
data = request.data
email = data['email']
payment_method_id = data['payment_method_id'] extra_msg = '' # add new variable to response message # checking if customer with provided email already exists customer_data = stripe.Customer.list(email=email).data
# if the array is empty it means the email has not been used yet if len(customer_data) == 0: # creating customercustomer = stripe.Customer.create(email=email, payment_method=payment_method_id) else:
customer = customer_data[0]
extra_msg = "Customer already existed."
return Response(status=status.HTTP_200_OK, data={'message': 'Success', 'data': {
'customer_id': customer.id, 'extra_msg': extra_msg}
})

We’ve just added fetching the list of users with their provided emails and checking if the returned array is empty or not. In the first case, it means no user was found, and we can create a new one. In the second case, we’re taking the first element of the array and returning it as our existing customer.

我们刚刚添加了使用提供的电子邮件获取用户列表,并检查返回的数组是否为空。 在第一种情况下,这意味着找不到用户,我们可以创建一个新用户。 在第二种情况下,我们将数组的第一个元素作为现有客户返回。

Note: Of course, the array returned from stripe.Customer.list may have more than one element, but for purpose of this article, we assume customer emails must be unique.

注意:当然,从stripe.Customer.list返回的数组可能具有多个元素,但是出于本文的目的,我们假设客户电子邮件必须唯一。

Let’s quickly check the current code. Refresh the browser, and send the same email again. You should see in the console the response contains the extra_msg key, and the customer_id is the same as the previous one. The Stripe dashboard also hasn’t change, and there’s still only one customer.

让我们快速检查一下当前代码。 刷新浏览器,然后再次发送相同的电子邮件。 您应该在控制台中看到响应中包含extra_msg键,而customer_id与上一个相同。 Stripe仪表板也没有更改,仍然只有一个客户。

Image for post

Let’s run one more test and send data with the email address test2@gmail.com.

让我们再进行一次测试,并通过电子邮件地址test2@gmail.com发送数据。

Image for post

What happened this time?

这次发生了什么事?

Image for post

The console showed us a different customer_id and an empty extra_msg. Now in the Stripe dashboard, we can see a new customer with the test2@gmail.com email address.

控制台向我们显示了一个不同的customer_id和一个空的extra_msg 。 现在,在Stripe仪表板中,我们可以看到具有test2@gmail.com电子邮件地址的新客户。

Image for post
Stripe dashboard: Customers ;ist
条纹仪表板:客户; ist

Our validation is working!

我们的验证有效!

Note: Normally you should somehow handle email validation and show users some message or do anything else to keep the flow of your app. But in our case, we won’t focus on it, and all the operations will be just applied to existing or newly created customers.

注意:通常,您应该以某种方式处理电子邮件验证,并向用户显示一些消息或执行其他任何操作以保持应用程序的正常运行。 但是,在我们的案例中,我们不会专注于此,所有操作都将仅应用于现有或新创建的客户。

创建PaymentIntent —向客户收取一次性费用 (Create PaymentIntent — charge the customer with a one-time fee)

Let’s achieve our third goal and charge the customer with a one-time fee. As mentioned before, we’ll use the PaymentIntentobject for that.

让我们实现我们的第三个目标,并向客户收取一次性费用。 如前所述,我们将PaymentIntent使用PaymentIntent对象。

# payments/views.py@api_view(['POST'])
def save_stripe_info(request): [...]
else:
customer = customer_data[0]
extra_msg = "Customer already existed." # add these linesstripe.PaymentIntent.create(
customer=customer,
payment_method=payment_method_id,
currency='pln',
# you can provide any currency you want
amount=999)
# it equals 9.99 PLN

We passed to the stripe.PaymentIntent.create method our customerobject, the payment_method_id, the currency, and the amount of the fee. Let’s send the form again and check what will happen in the Stripe dashboard. When you open the Payments tab, you should see something like this:

我们将我们的customer对象, payment_method_idcurrency和费用amount传递给stripe.PaymentIntent.create方法。 让我们再次发送表单,并检查Stripe仪表板中将发生的情况。 当您打开“ 付款”标签时,您应该会看到以下内容:

Image for post
Stripe dashboard: Payments
条纹仪表板:付款

It looks like the payment has been created but not completed. What happened? Let’s open the payment details and scroll down to see the events and logs.

似乎付款已创建但尚未完成。 发生了什么? 让我们打开付款详细信息并向下滚动以查看事件和日志。

Image for post
Stripe dashboard: Payment logs
条纹仪表板:付款日志

It seems like the payment requires confirmation. Let’s get back to the documentation and read once again about creating PaymentIntents:

这笔款项似乎需要确认。 让我们回到文档中并再次阅读有关创建PaymentIntent的信息:

“After the PaymentIntent is created, attach a payment method and confirm to continue the payment. (…) When confirm=true is used during creation, it is equivalent to creating and confirming the PaymentIntent in the same call (...) This parameter defaults to false.”

“创建PaymentIntent后,请附上付款方式并确认继续付款。 (…)在创建过程中使用confirm=true时,等效于在同一调用中创建并确认PaymentIntent (...),此参数默认为false 。”

It means that we have two possibilities: (1) Call the method stripe.PaymentIntent.confirm to confirm the payment or (2) set the parameter confirm=True in the stripe.PaymentIntent.create method. Let’s choose the second option and modify our code a little bit:

这意味着我们有两种可能性:(1)调用方法stripe.PaymentIntent.confirm确认付款,或(2)在stripe.PaymentIntent.create方法中设置参数stripe.PaymentIntent.create confirm=True 。 让我们选择第二个选项并稍微修改一下代码:

# payments/views.pystripe.PaymentIntent.create(customer=customer, payment_method=payment_method_id,  currency='pln', # you can provide any currency you wantamount=1500, # I modified amount to distinguish payments
confirm=True)

Send the form once again, and refresh the Stripe dashboard. You should see a new payment with the Succeeded status:

再次发送表单,并刷新Stripe仪表板。 你应该看到一个新的支付Succeeded状态:

Image for post

And what about the logs?

那日志呢?

Image for post
Stripe Dashboard — Payment logs
条纹仪表板—付款日志

Everything worked fine. The payment has been created and confirmed in one go. We’ve just accomplished out third goal.

一切正常。 付款已创建并一次性确认。 我们刚刚完成了第三个目标。

创建订阅 (Create Subscription)

Finally, we can set up our user’s subscription. According to the Stripe documentation, Subscription needs to be linked with a Price object, and the Price is usually assigned to some Product.

最后,我们可以设置用户的订阅。 根据Stripe文档, Subscription需要与Price对象链接,并且通常将Price分配给某些Product

To explain it better, let’s imagine different types of cinema tickets: regular, half-price, and free ones. In this case our Product would be the Ticket object with three different Prices. Just take a look at the the image below:

为了更好地解释它,让我们想象一下不同类型的电影票:普通票,半价票和免费票。 在这种情况下,我们的Product将是具有三个不同PriceTicket对象。 只需看下面的图片:

Image for post

In our project, we’ll just create a Product called Monthly Subscription for our app with a Price 50.00 PLN paid monthly.

在我们的项目中,我们将为应用创建一个名为“ Monthly SubscriptionProduct Monthly Subscription支付50.00 PLN的价格。

Stripe shares API requests to create all of the mentioned objects in the code. But there’s also another option — much faster and easier: using the dashboard. So let’s open the Products tab and click the Add Product button.

Stripe共享API请求,以在代码中创建所有提到的对象。 但是还有另一种选择-更快,更容易:使用仪表板。 因此,让我们打开“ 产品”选项卡,然后单击“添加产品”按钮。

Image for post
Stripe dashboard: Products
条纹仪表板:产品

Then fill in the Name and (optionally) Description fields:

然后填写名称和(可选)描述字段:

Image for post
Stripe dashboard: New product form
条纹仪表板:新产品形式

And create a Price with a recurring (monthly) billing period:

并创建一个Price与经常性(每月)结算周期:

Image for post
Stripe dashboard: New pricing form
条纹仪表板:新定价表

Great! Now you should see the new Product in your dashboard. Copy its Price’s ID (starting with price_ ), and edit our save_stripe_info.

大! 现在,您应该在仪表板中看到新Product 。 复制其Price的ID(以price_ ),然后编辑我们的save_stripe_info

# payments/views.py@api_view(['POST'])
def save_stripe_info(request): [...]stripe.Subscription.create(
customer=customer,
items=[
{
'price': 'price_' #here paste your price id
}
]
)

Everything seems fine. It should be working — shouldn’t it? Let’s check.

一切似乎都很好。 它应该正常工作-不是吗? 让我们检查。

Oh no! Have you just gotten an error similar to the one below?

不好了! 您是否刚收到与以下错误类似的错误?

stripe.error.InvalidRequestError: Request req_123: 
This customer has no attached payment source or default payment method.

What does it mean? Let’s get back to the documentation, where you’ll find very important information:

这是什么意思? 让我们回到文档中,您将在其中找到非常重要的信息:

Customer.invoice_settings.default_payment_method (optional)

Customer.invoice_settings.default_payment_method (optional)

“ID of a payment method that’s attached to the customer, to be used as the customer’s default payment method for subscriptions and invoices.”

“附加到客户的付款方式的ID,将用作客户用于订阅和发票的默认付款方式。”

This means when you want to charge your customer with recurring subscriptions, you have to assign default_payment_method first.

这意味着当您要向客户收取定期订阅费用时,必须首先分配default_payment_method

OK, let’s do it! Modify the stripe.Customer.create method:

好的,让我们一起做! 修改stripe.Customer.create方法:

customer = stripe.Customer.create(email=email,payment_method=payment_method_id,invoice_settings={
'default_payment_method': payment_method_id
}

)

And try again with a new email:

然后使用新电子邮件重试:

Image for post

You should see the Success message in your console, and when you refresh the Stripe dashboard, there should be a new payment:

您应该在控制台中看到Success消息,并且当您刷新Stripe仪表板时,应该有新的付款:

Image for post
Stripe dashboard: Payments
条纹仪表板:付款

And when you click on it, you’ll even see the next payment date:

当您单击它时,您甚至会看到下一个付款日期:

Image for post
Stripe dashboard: Subscriptions
条纹仪表板:订阅

Great! You’ve just finished the app. Congratulations!

大! 您刚刚完成了该应用程序。 恭喜你!

结论 (Conclusion)

I hope you’ll befriend Stripe, as it’s a very powerful library that can handle any payment nightmares you’ll encounter in your developer career.

我希望您成为Stripe的朋友,因为它是一个非常强大的库,可以处理您在开发人员职业生涯中遇到的任何付款噩梦。

I also recommend you read carefully through the Stripe documentation because there’s a lot of useful information that’ll help you avoid bugs and make your life easier.

我还建议您仔细阅读Stripe文档,因为这里有很多有用的信息,可以帮助您避免错误并简化生活。

翻译自: https://medium.com/better-programming/how-to-integrate-django-react-app-with-stripe-payments-95709b3f23e5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值