Django docking Alipay Alipay realized gold function

Many sites are in gold, like the integration of virtual currency, to obtain these often need to recharge. So the question is, how to achieve docking payment function Po Alipay gold in Django it? Lot of information online are electricity providers, who will order the system with such complex, gold and recharge functions required to implement so versatile.

The effect is as follows:

Here Insert Picture Description
Here Insert Picture Description

Here Insert Picture Description
Here Insert Picture Description

Django now to achieve docking Alipay feature it!

Log Alipay open platform

Click to enter ants gold dress open platform https://open.alipay.com/platform/home.htm
enter Alipay sandbox environment https://openhome.alipay.com/platform/appDaily.htm?tab=info

Here Insert Picture Description
As shown, this is to configure your sandbox environment, on the left there is a sandbox sandbox tool Alipay Android version download, sandbox account is your test account.

Download Alipay open platform development assistant

Click to open the download link

Here Insert Picture Description
Open the tool, generate keys, and then take good care of! !
Here Insert Picture Description
Here Insert Picture Description

Save the key

Here Insert Picture Description
The public key 2048 that application just rename: pub_2048.txt, 2048 to rename the application of the private key: private_2048.txt, these two files in the project directory.
Note: The start and end keys must add the following string! ! !

-----BEGIN PRIVATE KEY-----
这里粘贴里面的密钥
-----END PRIVATE KEY-----

Here Insert Picture Description

Copy the public key Alipay and save

Here Insert Picture Description
Alipay public put this copy, rename alipay_key_2048.txt, saved to the project directory, add the following string note

-----BEGIN PRIVATE KEY-----
这里粘贴里面的密钥
-----END PRIVATE KEY-----

Setting Public Key

To just a pub_2048.txtcopy of the string to the inside as follows:

Here Insert Picture Description

Here Insert Picture Description

Alipay debug interfaces

from datetime import datetime


from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from urllib.parse import quote_plus
from base64 import decodebytes, encodebytes

import json


class AliPay(object):
    """
    支付宝支付接口
    """

    def __init__(self, appid, app_notify_url, app_private_key_path,
                 alipay_public_key_path, return_url, debug=False):
        self.appid = appid
        self.app_notify_url = app_notify_url
        self.app_private_key_path = app_private_key_path
        self.app_private_key = None
        self.return_url = return_url
        with open(self.app_private_key_path) as fp:
            self.app_private_key = RSA.importKey(fp.read())

        self.alipay_public_key_path = alipay_public_key_path
        with open(self.alipay_public_key_path) as fp:
            self.alipay_public_key = RSA.import_key(fp.read())

        if debug is True:
            self.__gateway = "https://openapi.alipaydev.com/gateway.do"
        else:
            self.__gateway = "https://openapi.alipay.com/gateway.do"

    def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
        biz_content = {
            "subject": subject,
            "out_trade_no": out_trade_no,
            "total_amount": total_amount,
            "product_code": "FAST_INSTANT_TRADE_PAY",
            # "qr_pay_mode":4
        }

        biz_content.update(kwargs)
        data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
        return self.sign_data(data)

    def build_body(self, method, biz_content, return_url=None):
        data = {
            "app_id": self.appid,
            "method": method,
            "charset": "utf-8",
            "sign_type": "RSA2",
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "version": "1.0",
            "biz_content": biz_content
        }

        if return_url is not None:
            data["notify_url"] = self.app_notify_url
            data["return_url"] = self.return_url

        return data

    def sign_data(self, data):
        data.pop("sign", None)
        # 排序后的字符串
        unsigned_items = self.ordered_data(data)
        unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
        sign = self.sign(unsigned_string.encode("utf-8"))
        # ordered_items = self.ordered_data(data)
        quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)

        # 获得最终的订单信息字符串
        signed_string = quoted_string + "&sign=" + quote_plus(sign)
        return signed_string

    def ordered_data(self, data):
        complex_keys = []
        for key, value in data.items():
            if isinstance(value, dict):
                complex_keys.append(key)

        # 将字典类型的数据dump出来
        for key in complex_keys:
            data[key] = json.dumps(data[key], separators=(',', ':'))

        return sorted([(k, v) for k, v in data.items()])

    def sign(self, unsigned_string):
        # 开始计算签名
        key = self.app_private_key
        signer = PKCS1_v1_5.new(key)
        signature = signer.sign(SHA256.new(unsigned_string))
        # base64 编码,转换为unicode表示并移除回车
        sign = encodebytes(signature).decode("utf8").replace("\n", "")
        return sign

    def _verify(self, raw_content, signature):
        # 开始计算签名
        key = self.alipay_public_key
        signer = PKCS1_v1_5.new(key)
        digest = SHA256.new()
        digest.update(raw_content.encode("utf8"))
        if signer.verify(digest, decodebytes(signature.encode("utf8"))):
            return True
        return False

    def verify(self, data, signature):
        if "sign_type" in data:
            sign_type = data.pop("sign_type")
        # 排序后的字符串
        unsigned_items = self.ordered_data(data)
        message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
        return self._verify(message, signature)


def get_alipay_url(app_id, order_sn, order_mount):
    alipay = AliPay(
        appid=app_id,
        app_notify_url="http://127.0.0.1:8000/alipay/return/",
        app_private_key_path="../trade/keys/private_2048.txt",
        alipay_public_key_path="../trade/keys/alipay_key_2048.txt",  # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥,
        debug=True,  # 默认False,
        return_url="http://127.0.0.1:8000/alipay/return/"
    )

    url = alipay.direct_pay(
        subject=order_sn,
        out_trade_no=order_sn,
        total_amount=order_mount,
    )
    re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)

    return re_url


if __name__ == "__main__":
    url = get_alipay_url(
        '2016092600597838',
        '201902923423436',
        1.00
    )
    print(url)

If the url output can open and use the sandbox account to pay, the foregoing description is configured, it can be written in the view.

Orders database design model

from django.db import models
from django.conf import settings
from django.utils.encoding import python_2_unicode_compatible

from questioning.utils.models import CreatedUpdatedMixin

@python_2_unicode_compatible
class OrderInfo(CreatedUpdatedMixin, models.Model):
    '''
    充值订单详情
    '''
    ORDER_STATUS = (
    ('TRADE_SUCCESS', '交易支付成功'),
    ('TRADE_CLOSED', '未付款交易超时关闭'),
    ('WAIT_BUYER_PAY', '交易创建'),
    ('TRADE_FINISHED', '交易结束'),
    ('paying', '待支付'),
)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name='用户')
    order_sn = models.CharField(max_length=30, null=True, blank=True, unique=True, verbose_name='订单号')
    trade_no = models.CharField(max_length=100, unique=True, null=True, blank=True, verbose_name='支付订单号')

    pay_status = models.CharField(choices=ORDER_STATUS, max_length=40, verbose_name='订单状态', default='paying')
    order_mount = models.DecimalField(verbose_name="充值金额", max_digits=10,
                                decimal_places=2, default=0.00)


    class Meta:
        verbose_name = "充值订单"
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.order_sn

Note recharge amount to be set to the models.DecimalFieldcurrency type
and then imported into the database

View Writing functions

class AlipayView(LoginRequiredMixin, AuthorRequiredMixin, View):
    """
    支付宝支付
    get方法实现支付宝return_url,如果没有实现也无所谓,post同样可以更新状态
    post方法实现支付宝notify_url,异步更新

    支付宝返回的url如下:
    #http://127.0.0.1:8000/alipay/return/?
    # charset=utf-8&
    # out_trade_no=201902923423436&
    # method=alipay.trade.page.pay.return&
    # total_amount=1.00&
    # sign=CDBMY9NBsp4KICdQoBEVxGWobd0N8y4%2BU09stzUWwlNtLr7ZpELJdM5js20wXv%2FCPp0FGPbRW1YS9DRx0CnKJULZZMqysBUMH2FL39sS0Fgstgy1ydTs7ySXdHziJV0inI%2BDWAsebQqtjk5gQEweUstc%2B%2BnzjdgAulpvWzfJsbknS%2BqUfktSdF2ZOWGhr1CFlfsMFEDS2nzQv4K3E%2BNaeylkzUnRe9M1sjIL%2FYR0wVZ5A3OfHLPf9HzC2B8%2FLu4g7N5Vctkqp2aerDvIkN5SNmDnRGyjOt2b%2BOsLMqG4X06JSsrZT6Ln8PimsrkSOIGbj0gCqscx7BwZfmCQePlCw%3D%3D&
    # trade_no=2019082622001426981000041778&
    # auth_app_id=2016092600597838&
    # version=1.0&app_id=2016092600597838&
    # sign_type=RSA2&
    # seller_id=2088102177296610&
    # timestamp=2019-08-26+13%3A51%3A01
    """
    def dispatch(self, request, *args, **kwargs):
        self.alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=settings.APP_NOTIFY_URL,
            app_private_key_path=settings.APP_PRIVATE_KEY_PATH,
            alipay_public_key_path=settings.ALIPAY_PUBLIC_KEY_PATH,
            debug=settings.ALIPAY_DEBUG,
            return_url=settings.RETURN_URL
        )
        #处理返回的url参数
        callback_data = {}
        for key, value in request.GET.items():
            callback_data[key] = value
        sign = callback_data.pop('sign', None)
        self.order_sn = callback_data.get('out_trade_no', None) #订单号
        self.trade_no = callback_data.get('trade_no', None) #支付宝订单号

        # 验证签名
        self.verify = self.alipay.verify(callback_data, sign)
        return super(AlipayView, self).dispatch(request, *args, **kwargs)


    def get(self, request):
        """处理支付宝return_url返回"""

        if self.verify:
            self.deposit()
            #返回个人中心页面
            return redirect(reverse('users:detail', kwargs={
                'username': request.user.username
            }))

    def post(self, request):
        """
        处理notify_url
        """
        if self.verify:
            self.deposit()

        return Response('success')

    def deposit(self):
        """充值操作

        1.更新用户的金币信息
        2.更新订单状态为交易成功
        """

        # 数据库中查询订单记录
        order = OrderInfo.objects.get(order_sn=self.order_sn)
        order.trade_no = self.trade_no  # 支付宝订单号

        # 把人民币转换成对应的金币
        rmb = order.order_mount
        money = convert_rmb_to_money(rmb)

        # 更新用户的金币
        order.user.money += Decimal(money)
        order.user.save()
        # 订单状态置为交易成功
        order.pay_status = 'TRADE_SUCCESS'
        order.save()

When the user payment is successful, it will jump back, that is return_url, to deal with this is to get the method used to update the user's gold and order.

Guess you like

Origin www.cnblogs.com/PyKK2019/p/11413468.html