All Projects → ZTCooper → Weixin_demo

ZTCooper / Weixin_demo

Licence: mit
微信小程序后端开发demo,包括获取openid、微信支付(统一下单、支付回调、企业付款

Programming Languages

python
139335 projects - #7 most used programming language

Labels

Projects that are alternatives of or similar to Weixin demo

Docker Elk Tutorial
docker-elk-tutorial + django + logging
Stars: ✭ 69 (-6.76%)
Mutual labels:  django
Django React Boilerplate
Django, React, Bootstrap 4 with Python 3 and webpack project boilerplate
Stars: ✭ 1,164 (+1472.97%)
Mutual labels:  django
Django Likes
Django app providing view interface to django-secretballot.
Stars: ✭ 72 (-2.7%)
Mutual labels:  django
Djangosaml2idp
SAML 2.0 Identity Provider in Django
Stars: ✭ 69 (-6.76%)
Mutual labels:  django
Trello Clone
A Trello clone made using Django and React
Stars: ✭ 70 (-5.41%)
Mutual labels:  django
Django Rest React Pycon
🐍 Demo repo for Pycon X talk "Decoupling Django with Django REST (and a sprinkle of React)"
Stars: ✭ 72 (-2.7%)
Mutual labels:  django
Loonflow
基于django的工作流引擎,工单(a workflow engine base on django python)
Stars: ✭ 1,153 (+1458.11%)
Mutual labels:  django
See
基于开源组件(Inception & SQLAdvisor & SOAR)的SQL审核&SQL优化的Web平台
Stars: ✭ 1,187 (+1504.05%)
Mutual labels:  django
Shopping cart
A basic shopping cart for digital products. Made with Django
Stars: ✭ 70 (-5.41%)
Mutual labels:  django
Qblog
🐍A blog base on Python+Django.
Stars: ✭ 72 (-2.7%)
Mutual labels:  django
Cookiecutter Django Ansible
Powered by Cookiecutter, Cookiecutter Django Ansible is a framework for jumpstarting an ansible project for provisioning a server that is ready for your cookiecutter-django application.
Stars: ✭ 69 (-6.76%)
Mutual labels:  django
Bugsnag Python
Official bugsnag error monitoring and error reporting for django, flask, tornado and other python apps.
Stars: ✭ 69 (-6.76%)
Mutual labels:  django
Myblog
python 博客系统,基于django
Stars: ✭ 70 (-5.41%)
Mutual labels:  django
Django Webpacker
A django compressor tool that bundles css, js files to a single css, js file with webpack and updates your html files with respective css, js file path.
Stars: ✭ 69 (-6.76%)
Mutual labels:  django
Papermerge
Open Source Document Management System for Digital Archives (Scanned Documents)
Stars: ✭ 1,177 (+1490.54%)
Mutual labels:  django
Django Vue Template
Django Rest + Vue JS Template
Stars: ✭ 1,155 (+1460.81%)
Mutual labels:  django
Pwned Passwords Django
Utilities for working with the Pwned Passwords database from Django.
Stars: ✭ 71 (-4.05%)
Mutual labels:  django
Django Admin Material
A Django Admin interface based on Material Design by Google
Stars: ✭ 74 (+0%)
Mutual labels:  django
Pyarweb
El sitio web de Python Argentina
Stars: ✭ 73 (-1.35%)
Mutual labels:  django
Ara
ARA Records Ansible and makes it easier to understand and troubleshoot.
Stars: ✭ 1,176 (+1489.19%)
Mutual labels:  django

weixin_demo

List

Introduction

配置必须参数(config.py

# 配置必须参数 

APPID = ""      # 小程序ID
SECRET = ""
MCHID = ""      # 商户号
KEY = ""
NOTIFY_URL = ""     # 统一下单后微信回调地址,api demo见notify_view_demo.py
# 证书路径
'''
发起企业付款时需携带的证书
登录微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->证书下载
下载apiclient_cert.p12
python无法使用双向证书,使用openssl导出:
    openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem
    openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem
导出apiclient_key.pem时需输入PEM phrase, 此后每次发起请求均要输入,可使用openssl解除:
    openssl rsa -in apiclient_key.pem -out apiclient_key.pem.unsecure
'''
WX_CERT_PATH = "path/to/apiclient_cert.pem"
WX_KEY_PATH = "path/to/apiclient_key.pem.unsecure"

获取openid(obtain_openid_demo.py

# 获取openid, 支付提现均需要

import requests

from config import APPID, SECRET


class OpenidUtils(object):

    def __init__(self, jscode):
        self.url = "https://api.weixin.qq.com/sns/jscode2session"
        self.appid = APPID
        self.secret = SECRET
        self.jscode = jscode    # 前端传回的动态jscode

    def get_openid(self):
        # url一定要拼接,不可用传参方式
        url = self.url + "?appid=" + self.appid + "&secret=" + self.secret + "&js_code=" + self.jscode + "&grant_type=authorization_code"
        r = requests.get(url)
        print(r.json())
        openid = r.json()['openid']

        return openid

支付(pay_demo.py

即统一下单(官方文档此处不够清晰,可参考注释

# 统一下单

import requests
import hashlib
import xmltodict
import time
import random
import string

from config import APPID, MCHID, KEY, NOTIFY_URL


# 生成订单号
def generate_out_trade_no():
    # 20位
    seeds = '1234567890'
    random_str = []
    for i in range(6):
        random_str.append(choice(seeds))
    subfix =  ''.join(random_str)

    return datetime.now().strftime("%Y%m%d%H%M%S") + subfix

# 生成nonce_str
def generate_randomStr():
    return ''.join(random.sample(string.ascii_letters + string.digits, 32))

# 生成签名
def generate_sign(param):
    stringA = ''

    ks = sorted(param.keys())
    # 参数排序
    for k in ks:
        stringA += k + "=" + str(param[k]) + "&"
    # 拼接商户KEY
    stringSignTemp = stringA + "key=" + KEY

    # md5加密
    hash_md5 = hashlib.md5(stringSignTemp.encode('utf8'))
    sign = hash_md5.hexdigest().upper()

    return sign

# 发送xml请求
def send_xml_request(url, param):
    # dict 2 xml
    param = {'root': param}
    xml = xmltodict.unparse(param)

    response = requests.post(url, data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'})
    # xml 2 dict
    msg = response.text
    xmlmsg = xmltodict.parse(msg)

    return xmlmsg

# 统一下单
def generate_bill(out_trade_no, fee, openid):
    url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
    nonce_str = generate_randomStr()        # 订单中加nonce_str字段记录(回调判断使用)
    out_trade_no = generate_out_trade_no()     # 支付单号,只能使用一次,不可重复支付
    
    '''
    order.out_trade_no = out_trade_no
    order.nonce_str = nonce_str
    order.save()
    '''

    # 1. 参数
    param = {
        "appid": APPID,
        "mch_id": MCHID,    # 商户号
        "nonce_str": nonce_str,     # 随机字符串
        "body": 'TEST_pay',     # 支付说明
        "out_trade_no": out_trade_no,   # 自己生成的订单号
        "total_fee": fee,
        "spbill_create_ip": '127.0.0.1',    # 发起统一下单的ip
        "notify_url": NOTIFY_URL,
        "trade_type": 'JSAPI',      # 小程序写JSAPI
        "openid": openid,
    }
    # 2. 统一下单签名
    sign = generate_sign(param)
    param["sign"] = sign  # 加入签名
    # 3. 调用接口
    xmlmsg = send_xml_request(url, param)
    # 4. 获取prepay_id
    if xmlmsg['xml']['return_code'] == 'SUCCESS':
        if xmlmsg['xml']['result_code'] == 'SUCCESS':
            prepay_id = xmlmsg['xml']['prepay_id']
            # 时间戳
            timeStamp = str(int(time.time()))
            # 5. 根据文档,六个参数,否则app提示签名验证失败,https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12
            data = {
                "appid": APPID,
                "partnerid": MCHID,
                "prepayid": prepay_id,
                "package": "Sign=WXPay",
                "noncestr": nonce_str,
                "timestamp": timeStamp,
            }
            # 6. paySign签名
            paySign = generate_sign(data)
            data["paySign"] = paySign  # 加入签名
            # 7. 传给前端的签名后的参数
            return data

支付回调(notify_view_demo.py

支付回调接口方法

# 统一下单回调处理

import xmltodict

from django.http import HttpResponse

def payback(request):
    msg = request.body.decode('utf-8')
    xmlmsg = xmltodict.parse(msg)

    return_code = xmlmsg['xml']['return_code']

    if return_code == 'FAIL':
        # 官方发出错误
        return HttpResponse("""<xml><return_code><![CDATA[FAIL]]></return_code>
                            <return_msg><![CDATA[Signature_Error]]></return_msg></xml>""",
                            content_type='text/xml', status=200)
    elif return_code == 'SUCCESS':
        # 拿到这次支付的订单号
        out_trade_no = xmlmsg['xml']['out_trade_no']
        # order = Order.objects.get(out_trade_no=out_trade_no)
        if xmlmsg['xml']['nonce_str'] != order.nonce_str:
            # 随机字符串不一致
            return HttpResponse("""<xml><return_code><![CDATA[FAIL]]></return_code>
                                        <return_msg><![CDATA[Signature_Error]]></return_msg></xml>""",
                                content_type='text/xml', status=200)

        # 根据需要处理业务逻辑

        return HttpResponse("""<xml><return_code><![CDATA[SUCCESS]]></return_code>
                            <return_msg><![CDATA[OK]]></return_msg></xml>""",
                            content_type='text/xml', status=200)

提现(withdraw_demo.py

即企业付款(无回调,需使用双向证书
登录微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->证书下载
下载apiclient_cert.p12
python无法使用双向证书,使用openssl导出:

openssl pkcs12 -clcerts -nokeys -in apiclient_cert.p12 -out apiclient_cert.pem
openssl pkcs12 -nocerts -in apiclient_cert.p12 -out apiclient_key.pem

导出apiclient_key.pem时需输入PEM phrase, 此后每次发起请求均要输入,可使用openssl解除:

openssl rsa -in apiclient_key.pem -out apiclient_key.pem.unsecure
# 提现(企业付款

import xmltodict
import requests
import hashlib
import random
import string

from config import KEY, APPID, MCHID, WX_CERT_PATH, WX_KEY_PATH

# 生成nonce_str
def generate_randomStr():
    return ''.join(random.sample(string.ascii_letters + string.digits, 32))

# 生成签名
def generate_sign(param):
    stringA = ''

    ks = sorted(param.keys())
    # 参数排序
    for k in ks:
        stringA += (k + '=' + param[k] + '&')
    # 拼接商户KEY
    stringSignTemp = stringA + "key=" + KEY

    # md5加密
    hash_md5 = hashlib.md5(stringSignTemp.encode('utf8'))
    sign = hash_md5.hexdigest().upper()

    return sign

# 发送携带证书的xml请求
def send_cert_request(url, param):
    # dict 2 xml
    param = {'root': param}
    xml = xmltodict.unparse(param)
    
    response = requests.post(url, data=xml.encode('utf-8'),
                             headers={'Content-Type': 'text/xml'},
                             cert=(WX_CERT_PATH, WX_KEY_PATH))
    # xml 2 dict
    msg = response.text
    xmlmsg = xmltodict.parse(msg)

    return xmlmsg


def withdraw(self, openid, withdraw_value, withdraw_trade_no):
    url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers"

    param = {
        "mch_appid": APPID,
        "mchid": MCHID,     # 商户号
        "nonce_str": generate_randomStr(),      # 随机字符串
        "partner_trade_no": withdraw_trade_no,
        "openid": openid,       # 获取openid见obtain_openid_demo.py
        "check_name": "NO_CHECK",
        "amount": withdraw_value,       # 提现金额,单位为分
        "desc": "TEST_withdraw",        # 提现说明
        "spbill_create_ip": "127.0.0.1",    # 发起提现的ip
    }

    sign = generate_sign(param)
    param["sign"] = sign
    # 携带证书
    xmlmsg = send_cert_request(url, param)

    print(xmlmsg)

    if xmlmsg['xml']['return_code'] == 'SUCCESS' and xmlmsg['xml']['result_code'] == 'SUCCESS':
        return xmlmsg
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].