当前位置 主页 > 服务器问题 > Linux/apache问题 >

    django多种支付、并发订单处理实例代码

    栏目:Linux/apache问题 时间:2019-12-13 16:28

    django实现多种支付方式

    '''
    #思路
      
      我们希望,通过插拔的方式来实现多方式登录,比如新增一种支付方式,那么只要在项目中新增一个py文件,导入里面的pay方法就可以了,这样在支付业务中支付语句是不发生变化的。
      所以就可以使用python的鸭子类型及面向对象的反射方法来实现功能
    
    '''
    
    ##新建一个Pay文件夹,里面放支付方式.py文件
    #Alipay.py
    class Alipay:
      def pay(self):
        pass
    #Visapay.py
    class Visapay:
      def pay(self):
        pass
    #Wxpay.py(完全按照接口文档来得)
    import time
    #记得导入商户号和key哦!
    from app01.wx import settings
    class Wxpay:
      def pay(self,order_data):
        self.order_id = order_data["order_id"]
        self.open_id = order_data['open_id']
        self.ip = order_data['ip']
        data_body = self.get_body_data()
        import requests
        url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
        response = requests.post(url, data_body.encode("utf-8"), headers={'content-type': "application/xml"})
        res_dict = self.xml_to_dic(response.content)
        timeStamp = str(int(time.time()))
        paySign = self.get_pay_sign(res_dict, timeStamp)
    
        data_dic = {
          'timeStamp': timeStamp,
          'nonceStr': res_dict['nonce_str'],
          'package': f"prepay_id={res_dict['prepay_id']}",
          'signType': 'MD5',
          "paySign": paySign,
        }
    
        return data_dic
    
      def get_pay_sign(self, res_dict, timeStamp):
        print("res_dict", res_dict)
        data_dic = {
          'appId': res_dict['appid'],
          'timeStamp': timeStamp,
          'nonceStr': res_dict['nonce_str'],
          'package': f"prepay_id={res_dict['prepay_id']}",
          "signType": "MD5"
        }
        sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
        sign_str = f"{sign_str}&key={settings.pay_apikey}"
        import hashlib
        md5 = hashlib.md5()
        md5.update(sign_str.encode("utf-8"))
        sign = md5.hexdigest()
        return sign.upper()
    
      def xml_to_dic(self, xml_data):
        import xml.etree.ElementTree as ET
        '''
        xml to dict
        :param xml_data:
        :return:
        '''
        xml_dict = {}
        root = ET.fromstring(xml_data)
        for child in root:
          xml_dict[child.tag] = child.text
        return xml_dict
    
      def get_random(self):
        import random
        data = "123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP"
        nonce_str = "".join(random.sample(data, 30))
        return nonce_str
    
    
    
      def get_sign(self):
        data_dic = {
          "nonce_str": self.nonce_str,
          "out_trade_no": self.out_trade_no,
          "spbill_create_ip": self.spbill_create_ip,
          "notify_url": self.notify_url,
          "openid": self.open_id,
          "body": self.body,
          "trade_type": "JSAPI",
          "appid": self.appid,
          "total_fee": "1",
          "mch_id": self.mch_id
        }
    
        sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
        sign_str = f"{sign_str}&key={settings.pay_apikey}"
        import hashlib
        md5 = hashlib.md5()
        md5.update(sign_str.encode("utf-8"))
        sign = md5.hexdigest()
        return sign.upper()
    
      def get_body_data(self):
        self.appid = settings.AppId
        # openid=self.open_id
        self.mch_id = str(settings.pay_mchid)
        self.nonce_str = self.get_random()
        self.out_trade_no = self.order_id
        self.spbill_create_ip = self.ip
        self.notify_url = "https://www.test.com"
        self.body = "老男孩学费"
        self.sign = self.get_sign()
        body_data = f"""
          <xml>
            <appid>{self.appid}</appid>
            <mch_id>{self.mch_id}</mch_id>
            <nonce_str>{self.nonce_str}</nonce_str>
            <sign>{self.sign}</sign>
            <body>{self.body}</body>
            <out_trade_no>{self.out_trade_no}</out_trade_no>
            <total_fee>1</total_fee>
            <spbill_create_ip>{ self.spbill_create_ip}</spbill_create_ip>
            <notify_url>{self.notify_url}</notify_url>
            <openid>{self.open_id}</openid>
            <trade_type>JSAPI</trade_type> 
          </xml>"""
        return body_data
      
      
      
    ##调用支付方法的语句(一般支付都是发生在订单创建好之后)
    import importlib
    from rest_framework.response import Response
    pay_method = "Wxpay" #这里是举例子,所以把pay_method写死了,正常情况下,应该是外面传来的支付方式,然后用pay_method接收
    try:
      #用字符串导入支付方式的py文件,例如这里的app01.Pay.{pay_method}
      pay_field = importlib.import_module(f"app01.Pay.{pay_method}")
      
      #用反射拿到该文件下面的类
      pay_method_class = getattr(pay_field, pay_method)
    except:
      return Response({"code": 205, "msg": "错误的支付方式"})
    
    order_data['ip'] = host_ip
    order_data['open_id'] = open_id
    
    #完成支付,并把支付数据返回
    pay_data = pay_method_class().pay(order_data)
    '''
    这里直接用反射拿到的支付类,然后使用它的pay方法,完成支付
    '''
    return Response({"code": 200, "msg": "ok", "data": pay_data})