python 小程序支付代码

import io
import json
import os
import time
from urllib.parse import quote
import requests
from Crypto.Cipher import AES
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from django.conf import settings
from django.utils import timezone
from django_redis import get_redis_connection
from requests_toolbelt import MultipartEncoder
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import base64

APPID = ""
MCHID = ""
NOTIFY_URL = ""
SERIAL_NO = ""

class Pay():
    def __init__(self):
        # =======【基本信息设置】=====================================
        self.appid = APPID
        self.mchid = MCHID
        self.notify_url = NOTIFY_URL
        self.serial_no = SERIAL_NO

    def get_head(self, method, uri, data=None):
        """
        请求头加密
        """
        timestamp = int(time.time())
        nonce_str = self.get_nonce_str()
        sign_str = f"{method}\n{uri}\n{timestamp}\n{nonce_str}\n"
        if data:
            sign_str += f'{data}\n'
        else:
            sign_str += f'\n'
        sign = self.get_sign(sign_str)
        headers = {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'User-Agent': '*/*',
            "Authorization": f'WECHATPAY2-SHA256-RSA2048 mchid="{self.mchid}",nonce_str="{nonce_str}",signature="{sign}",timestamp="{timestamp}",serial_no="{self.serial_no}"'
        }
        return headers

    def get_nonce_str(self, length=32):
        """生成随机字符串"""
        import random
        chars = "abcdefghijklmnopqrstuvwxyz0123456789"
        strs = []
        for x in range(length):
            strs.append(chars[random.randrange(0, len(chars))])
        return "".join(strs)

    def make_order(self, trade_no, total_amount, openid, desc):
        url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi'
        data = {
            'appid': self.appid,  # appid
            'mchid': self.mchid,  # 商户号
            'description': desc,  # 商品描述
            'out_trade_no': str(trade_no),  # 商户订单号
            'notify_url': self.notify_url,  # 微信支付结果异步通知地址
            'amount': {
                'total': int(total_amount),
            },
            "payer": {
                "openid": openid
            }
        }
        try:
            res = requests.post(url, json=data,
                                headers=self.get_head(data=json.dumps(data), method='POST',
                                                      uri='/v3/pay/transactions/jsapi')).json()
        except:
            return False, '微信下单失败'
        if 'prepay_id' in res:
            return True, res['prepay_id']
        else:
            return False, res['message']

    def close_order(self, trade_no):
        # 关闭订单
        url = f'https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{trade_no}/close'
        data = {
            "mchid": self.mchid
        }
        res = requests.post(url, json=data,
                            headers=self.get_head(data=json.dumps(data), method='POST',
                                                  uri=f'/v3/pay/transactions/out-trade-no/{trade_no}/close'))
        return res

    def get_order(self, trade_no):
        # 查询订单
        url = f'https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/{trade_no}?mchid={self.mchid}'
        res = requests.get(
            url, headers=self.get_head(
                method='GET',
                uri=f'/v3/pay/transactions/out-trade-no/{trade_no}?mchid={self.mchid}'
            )
        )
        print(res.json())

    def key_value_url(self, value, urlencode):
        """
        将键值对转为 key1=value1&key2=value2
        对参数按照key=value的格式,并按照参数名ASCII字典序排序
        """
        slist = sorted(value)
        buff = []
        for k in slist:
            v = quote(value[k]) if urlencode else value[k]
            buff.append("{0}={1}".format(k, v))

        return "&".join(buff)

    def get_sign(self, sign_str):
        if not settings.DEBUG:
            rsa_key = RSA.importKey(open(os.path.join(settings.BASE_DIR, 'shishi/wx_cert/apiclient_key.pem')).read())
        else:
            rsa_key = RSA.importKey(open(os.path.join(settings.BASE_DIR, 'wx_cert/apiclient_key.pem')).read())
        signer = pkcs1_15.new(rsa_key)
        digest = SHA256.new(sign_str.encode('utf8'))
        sign = base64.b64encode(signer.sign(digest)).decode('utf-8')
        return sign

    def format(self, prepay_id):
        # 给前端格式化
        timestamp = int(time.time())
        nonce_str = self.get_nonce_str()
        package = f'prepay_id={prepay_id}'
        sign_type = 'RSA'
        data = {
            'timeStamp': timestamp,
            'nonceStr': nonce_str,
            'package': package,
            'signType': sign_type,
        }
        sign_str = f'{self.appid}\n{timestamp}\n{nonce_str}\n{package}\n'
        sign = self.get_sign(sign_str)
        data['paySign'] = sign
        return data

    @staticmethod
    def decrypt(nonce, ciphertext, associated_data):
        key = MY
        key_bytes = str.encode(key)
        nonce_bytes = str.encode(nonce)
        ad_bytes = str.encode(associated_data)
        data = base64.b64decode(ciphertext)
        aesgcm = AESGCM(key_bytes)
        return aesgcm.decrypt(nonce_bytes, data, ad_bytes)

    def refunds(self, trade_no, refund_no, money):
        # 退款
        url = 'https://api.mch.weixin.qq.com/v3/refund/domestic/refunds'
        data = {
            "out_trade_no": trade_no,
            "out_refund_no": refund_no,
            "reason": "押金退款",
            "notify_url": "https://weixin.qq.com",
            "funds_account": "AVAILABLE",
            "amount": {
                "refund": money,
                "total": money,
                "currency": "CNY"
            }
        }
        try:
            res = requests.post(url, json=data,
                                headers=self.get_head(data=json.dumps(data), method='POST',
                                                      uri='/v3/refund/domestic/refunds')).json()
        except Exception as e:
            print(e)
            return False, '微信退款失败'
        if 'message' in res:
            return False, res['message']
        return True, ''

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值