在 Django 中集成 Paytm 支付网关
在 Django 中集成 Paytm 支付网关
在 Django 中集成 Paytm 支付网关
简介:这是学习如何在 Django 应用中集成支付功能的绝佳途径。Paytm 的官方文档在此。
注意:您需要拥有 Paytm 商户账户才能使用支付网关。
以下文档中提到了向网关发送请求的过程:
图片来源:Paytm
我们将从零开始创建一个 Django 应用来实现我们的目标。
步骤 0:设置项目
首先,我们将为我们的项目创建一个虚拟环境。
# Install Django & virtualenv if not already
$ pip install Django virtualenv
# create a new Django project
$ django-admin startproject pay2me
$ cd pay2me
# Initialize a new virtualenv with Py3 since Python 2 is dead
$ virtualenv env --python=python3
# Activate the virtual environment and intall Django
$ source ./env/bin/activate
(env)$ pip install Django
您可以使用该命令$ source ./env/bin/activate激活虚拟环境。
为了节省时间,我们将使用默认的 Django 用户模型进行身份验证,但如果您愿意,也可以使用自定义用户模型。
现在让我们为项目添加登录视图。打开pay2me/urls.py并向登录/注销视图添加条目。
from django.contrib.auth.views import LoginView
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', LoginView.as_view(), name='login'),
]
现在要创建登录和注销页面,我们首先需要迁移更改并创建一个超级用户。请在终端中运行以下命令。
(env)$ python manage.py makemigrations
(env)$ python manage.py migrate
(env)$ python manage.py createsuperuser
现在我们可以通过执行命令来运行服务器python manage.py runserver,然后访问http://localhost:8000/login来查看登录页面。
由于缺少登录页面模板,页面将无法加载,因此我们将创建一个模板LoginView。templates在项目根目录下创建一个目录,并registration在该目录下创建另一个目录。现在,在该目录中templates添加一个文件,并将以下内容添加到该文件中。login.htmlregistration
<!DOCTYPE html>
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
</body>
</html>
登录页面包含一个表单和一个csrf_token,该令牌将由系统提供,LoginView因此我们不必担心。
我们还需要进行一些修改pay2me/settings.py。打开文件,找到TEMPLATES设置并添加'templates'到DIRS列表中,它应该看起来像这样:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ['templates'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
这将有助于 Django 找到我们的registration/login.html模板。
模板已全部设置完毕,现在重启服务器并访问http://localhost:8000/login,登录表单应如下所示:
我们继续进行下一步。
第一步:制作用户界面
为了保持简洁,本文只有两页:
- 支付页面:我们将在此处输入需要支付的金额。
- 回调页面:从 Paytm 收到的包含支付状态的响应
让我们先创建一个新应用来组织这些功能。
(env)$ python manage.py startapp payments
首先,让我们将支付应用添加到项目中。为此,我们将把它添加'payments'到INSTALLED_APPS列表中pay2me/settings.py。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'payments',
]
现在让我们把模板文件添加pay.html到支付应用程序目录callback.html中。templates/payments
pay.html
<!DOCTYPE html>
<head>
<title>Payment Home</title>
</head>
<body>
<h2>Payment Home</h2>
{% if error %}
<h3>{{ error }}</h3>
{% endif %}
<form method="post">
{% csrf_token %}
<label for="username">Username: </label>
<input type="text" name="username" required>
<label for="password">Password: </label>
<input type="text" name="password" required>
<label for="amount">Amount: </label>
<input type="number" name="amount" value="100">
<input type="submit" name="submit" value="Submit" required>
</form>
</body>
</html>
回调.html
<!DOCTYPE html>
<head>
<title>Callback</title>
</head>
<body>
<h2>Callback Messsage: </h2> <br>
<h3> Checksum Verification: {{ message }} </h3> <br>
MID: {{ MID }} <br>
TXNID: {{ TXNID }} <br>
ORDERID: {{ ORDERID }} <br>
BANKTXNID: {{ BANKTXNID }} <br>
TXNAMOUNT: {{ TXNAMOUNT }} <br>
CURRENCY: {{ CURRENCY }} <br>
<h3> STATUS: {{ STATUS }} </h3> <br>
RESPCODE: {{ RESPCODE }} <br>
RESPMSG: {{ RESPMSG }} <br>
TXNDATE: {{ TXNDATE }} <br>
GATEWAYNAME: {{ GATEWAYNAME }} <br>
BANKNAME: {{ BANKNAME }} <br>
BIN_NAME: {{ BIN_NAME }} <br>
PAYMENTMODE: {{ PAYMENTMODE }} <br>
CHECKSUMHASH: {{ CHECKSUMHASH }}
</body>
</html>
支付页面会要求用户输入登录信息和支付金额,而回调页面则会显示 Paytm 在支付完成后提供的众多参数值。
步骤 2:创建交易模型
由于任何与支付相关的应用程序都需要交易,我们将按如下方式创建交易模型payments/models.py:
from django.db import models
from django.contrib.auth import get_user_model
User = get_user_model()
class Transaction(models.Model):
made_by = models.ForeignKey(User, related_name='transactions',
on_delete=models.CASCADE)
made_on = models.DateTimeField(auto_now_add=True)
amount = models.IntegerField()
order_id = models.CharField(unique=True, max_length=100, null=True, blank=True)
checksum = models.CharField(max_length=100, null=True, blank=True)
def save(self, *args, **kwargs):
if self.order_id is None and self.made_on and self.id:
self.order_id = self.made_on.strftime('PAY2ME%Y%m%dODR') + str(self.id)
return super().save(*args, **kwargs)
交易模型定义中,order_id是唯一的,并根据交易日期生成。我们可以看到,其中包含一个校验和,用于存储 Python 文件生成的校验和。
我们重写了该方法,使其能够根据交易的日期和时间save自动生成。order_id
让我们再次运行迁移,将事务模型添加到数据库中。
(env)$ python manage.py makemigration
(env)$ python manage.py migrate
步骤 3:添加 Paytm 设置
添加以下设置pay2me/settings.py:
PAYTM_MERCHANT_ID = '<your_merchant_id>'
PAYTM_SECRET_KEY = '<your_paytm_secret_key>'
PAYTM_WEBSITE = 'WEBSTAGING'
PAYTM_CHANNEL_ID = 'WEB'
PAYTM_INDUSTRY_TYPE_ID = 'Retail'
第四步:创建支付视图
Paytm在这里提供了一个校验和生成代码库,但该代码使用的是已弃用的库pycrypto。以下代码包含与最新pycryptodome库兼容的修改后的文件。请下载该文件payments并将其以文件名保存到您的应用程序中paytm.py。
现在我们来创建initiate_payment接收用户名、密码和金额的视图。打开payments/views.py并添加以下代码。
from django.shortcuts import render
from django.contrib.auth import authenticate, login as auth_login
from django.conf import settings
from .models import Transaction
from .paytm import generate_checksum, verify_checksum
def initiate_payment(request):
if request.method == "GET":
return render(request, 'payments/pay.html')
try:
username = request.POST['username']
password = request.POST['password']
amount = int(request.POST['amount'])
user = authenticate(request, username=username, password=password)
if user is None:
raise ValueError
auth_login(request=request, user=user)
except:
return render(request, 'payments/pay.html', context={'error': 'Wrong Accound Details or amount'})
transaction = Transaction.objects.create(made_by=user, amount=amount)
transaction.save()
merchant_key = settings.PAYTM_SECRET_KEY
params = (
('MID', settings.PAYTM_MERCHANT_ID),
('ORDER_ID', str(transaction.order_id)),
('CUST_ID', str(transaction.made_by.email)),
('TXN_AMOUNT', str(transaction.amount)),
('CHANNEL_ID', settings.PAYTM_CHANNEL_ID),
('WEBSITE', settings.PAYTM_WEBSITE),
# ('EMAIL', request.user.email),
# ('MOBILE_N0', '9911223388'),
('INDUSTRY_TYPE_ID', settings.PAYTM_INDUSTRY_TYPE_ID),
('CALLBACK_URL', 'http://127.0.0.1:8000/callback/'),
# ('PAYMENT_MODE_ONLY', 'NO'),
)
paytm_params = dict(params)
checksum = generate_checksum(paytm_params, merchant_key)
transaction.checksum = checksum
transaction.save()
paytm_params['CHECKSUMHASH'] = checksum
print('SENT: ', checksum)
return render(request, 'payments/redirect.html', context=paytm_params)
让我们逐部分地理解这个观点:
def initiate_payment(request):
if request.method == "GET":
return render(request, 'payments/pay.html')
第一步是检查请求方法。如果请求方法是GET,那么我们就直接返回支付页面。
try:
username = request.POST['username']
password = request.POST['password']
amount = int(request.POST['amount'])
user = authenticate(request, username=username, password=password)
if user is None:
raise ValueError
auth_login(request=request, user=user)
except:
return render(request, 'payments/pay.html', context={'error': 'Wrong Account Details or amount'})
然后,我们会验证用户在表单中输入的用户名和密码,并尝试登录。如果登录信息无效,则视图会返回登录页面并显示错误消息。
transaction = Transaction.objects.create(made_by=user, amount=amount)
transaction.save()
merchant_key = settings.PAYTM_SECRET_KEY
接下来,我们为用户创建一个 Transaction 对象,并从中获取商户密钥settings.py。
params = (
('MID', settings.PAYTM_MERCHANT_ID),
('ORDER_ID', str(transaction.order_id)),
('CUST_ID', str(transaction.made_by.email)),
('TXN_AMOUNT', str(transaction.amount)),
('CHANNEL_ID', settings.PAYTM_CHANNEL_ID),
('WEBSITE', settings.PAYTM_WEBSITE),
# ('EMAIL', request.user.email),
# ('MOBILE_N0', '9911223388'),
('INDUSTRY_TYPE_ID', settings.PAYTM_INDUSTRY_TYPE_ID),
('CALLBACK_URL', 'http://127.0.0.1:8000/callback/'),
# ('PAYMENT_MODE_ONLY', 'NO'),
)
paytm_params = dict(params)
然后我们为Paytm 校验和生成器创建所有设置,以便生成校验和。
checksum = generate_checksum(paytm_params, merchant_key)
transaction.checksum = checksum
transaction.save()
paytm_params['CHECKSUMHASH'] = checksum
接下来,在生成校验和之后,我们将校验和添加到paytm_params字典和Transaction对象中。
return render(request, 'payment/redirect.html', context=paytm_params)
最后我们返回redirect页面。
步骤 5:创建重定向页面
创建重定向页面payments/templates/payments/redirect.html:
<html>
<head>
<title>Merchant Check Out Page</title>
</head>
<body>
<h1>Please do not refresh this page...</h1>
<form method="post" action="https://securegw-stage.paytm.in/order/process/" name="f1">
<table>
<tbody>
<input type="hidden" name="MID" value="{{ MID }}">
<input type="hidden" name="WEBSITE" value="{{ WEBSITE }}">
<input type="hidden" name="ORDER_ID" value="{{ ORDER_ID }}">
<input type="hidden" name="CUST_ID" value="{{ CUST_ID }}">
<input type="hidden" name="INDUSTRY_TYPE_ID" value="{{ INDUSTRY_TYPE_ID }}">
<input type="hidden" name="CHANNEL_ID" value="{{ CHANNEL_ID }}">
<input type="hidden" name="TXN_AMOUNT" value="{{ TXN_AMOUNT }}">
<input type="hidden" name="CALLBACK_URL" value="{{ CALLBACK_URL }}">
<input type="hidden" name="CHECKSUMHASH" value="{{ CHECKSUMHASH }}">
</tbody>
</table>
<script type="text/javascript">
document.f1.submit();
</script>
</form>
</body>
</html>
重定向页面包含一个简单的表单,其中包含字典中的字段。我们使用 JavaScript 代码自动将表单提交到 Paytm 网关。
步骤 6:创建回调视图
回调视图是指当 Paytm 返回交易状态时将被调用的视图。
在以下回调视图中添加payments/views.py
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def callback(request):
if request.method == 'POST':
received_data = dict(request.POST)
paytm_params = {}
paytm_checksum = received_data['CHECKSUMHASH'][0]
for key, value in received_data.items():
if key == 'CHECKSUMHASH':
paytm_checksum = value[0]
else:
paytm_params[key] = str(value[0])
# Verify checksum
is_valid_checksum = verify_checksum(paytm_params, settings.PAYTM_SECRET_KEY, str(paytm_checksum))
if is_valid_checksum:
received_data['message'] = "Checksum Matched"
else:
received_data['message'] = "Checksum Mismatched"
return render(request, 'payments/callback.html', context=received_data)
return render(request, 'payments/callback.html', context=received_data)
回调视图接收来自 Paytm 服务器的 POST 请求。然后,我们将接收到的数据检索到一个字典中,并验证 Paytm 发送的校验和,以防止伪造请求。之后,我们返回包含交易详情和消息的页面。
步骤 7:创建路由。
最后一步,我们来创建视图的URL,结束这篇冗长的教程。urls.py在支付应用中创建/打开。添加以下路由。
from django.urls import path
from .views import initiate_payment, callback
urlpatterns = [
path('pay/', initiate_payment, name='pay'),
path('callback/', callback, name='callback'),
]
现在让我们把这些网址添加到……pay2me/urls.py
from django.urls import include
urlpatterns = [
# include
path('', include('payments.urls'))
]
测试运行:试用一种支付方式
现在让我们运行python manage.py runserver并访问http://localhost:8000/pay/来创建付款。
请填写表格。
这将跳转到 Paytm 支付网关。请使用任意虚拟支付方式。
您还可以选择交易状态(成功/失败)。
最后您将进入回调页面,该页面将显示交易状态。
Github:示例
以下是GitHub上上述示例代码的链接。
文章来源:https://dev.to/iiits-iota/paytm- payment-gateway-integration-in-django-1657





