美文网首页
接入威富通聚合支付平台

接入威富通聚合支付平台

作者: 叶叶阿姨 | 来源:发表于2021-06-08 10:42 被阅读0次

开发文档:https://open.swiftpass.cn/openapi?code=hsty
这个聚合平台大概是集合了微信、支付宝、云闪付等支付平台,大概有下图这么多:

企业微信截图_af26a470-e849-4a32-a9c5-19a3041298c6.png
一、付款码支付
付款码的大概业务功能:
收银员使用扫码设备读取用户微信/支付宝/云闪付等APP付款码以后,二维码或条码信息传送至商户收银台,由商户收银台或者商户后台调用该接口发起支付对用户进行收款
备注:我使用的是flask框架
1、支付
import time

import flask
from flask import Flask

from tool import *

app = Flask(__name__)


@app.route('/Pay', methods=['GET', 'POST'])
def gello_world():
    # 提交付款码支付API
    url = 'https://pay.hstypay.com/v2/pay/gateway'
    try:
        form_data = flask.request.get_data()  # 获取未经处理过的原始数据而不管内容类型
        json_data = json.loads(form_data.decode('utf-8'))  # 字符串转化为字典
        for i in ('service', 'mch_id', 'out_trade_no', 'body', 'total_fee', 'mch_create_ip', 'auth_code'):
            if i not in json_data.keys():
                # 将没有指定参添加上
                json_data[i] = None
        # 获取请求参数,并增加必带参数
        data = {
            "service": "unified.trade.micropay",  # 接口类型
            "mch_id": MCH_ID,  # 门店编号
            "out_trade_no": json_data["out_trade_no"],  # 商户订单号
            "body": json_data["body"],  # 商品描述
            "total_fee": json_data["total_fee"],  # 总金额
            "mch_create_ip": get_ip(),  # 终端IP
            "auth_code": json_data["auth_code"],  # 授权码
            "nonce_str": random_str()  # 随机字符串
        }

        sign = get_sign(data)  # 生成签名
        data["sign"] = sign  # 请求的参数中添加签名
        xml_str = trans_dict_to_xml(data)  # 字典转换xml
        res = requests.request('post', url, data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))  # 将xml数据转为python中的dict字典数据
        try:
            if result['xml']['err_code'] == 'USERPAYING':  # 需要输入密码的情况
                # 然后开始查询
                for i in range(6):
                    print(i+1, '次')
                    time.sleep(5)
                    rest = query_tool(data)
                    if i != 5 and rest['xml']['trade_state'] != 'SUCCESS':
                        continue
                    elif rest['xml']['trade_state'] == 'SUCCESS':
                        print('成功支付', rest)
                        result = query_tool(data)
                        result['xml']['pay_code'] = "支付成功"
                        return result
                    elif rest['xml']['trade_state'] != 'SUCCESS' and i == 5:  # 需要输入密码的情况
                        revoke_tool(data)  # 调用撤销接口
                        result = query_tool(data)
                        return result
                    else:
                        result = query_tool(data)
                        return result
            else:
                return result

        except:
            return result

    except Exception as e:
        print(e)
        raise e

这里我有使用到查询订单、签名、远程调取配置信息、生成随机字符串、字典转XML、获取本机ip,方法如下:
(远程调取配置信息)


def get_configuration_info():
    """
    获取前置机账户配置
    """
    url = "http://*******"
    Port = "***"
    CpnID = "***"
    res = requests.request('post', url, data={"Port": Port, "CpnID": CpnID})
    result = json.loads(res.content)
    result["data"] = json.loads(result["data"])
    aws_s3_url = result["data"]["cpnActMchinRcd"][0]["ActCfg"]
    res = requests.request('GET', aws_s3_url)
    aws_str = str(res.content)
    awx_json = parse.unquote(aws_str)
    for a in json.loads(awx_json[2:-1]):
        if a["Keyname"] == "mch_id":
            MCH_ID = a["Keyval"]
        elif a["Keyname"] == "key":
            MD5_KEY = a["Keyval"]
    return {'MCH_ID': MCH_ID, 'MD5_KEY': MD5_KEY}


MCH_ID = get_configuration_info()['MCH_ID']  # mch_id
MD5_KEY = get_configuration_info()['MD5_KEY']  # MD5密钥

(生成16位随机字符串)

def random_str(randomlength=16):
    """
    生成随机字符串
    :param randomlength: 字符串长度
    :return:
    """
    strs = ''
    chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
    length = len(chars) - 1
    random = Random()
    for i in range(randomlength):
        strs += chars[random.randint(0, length)]
    return strs

(计算签名)

def get_sign(data_dict):
    """
    签名函数
    :param data_dict: 需要签名的参数,格式为字典
    :param key: 密钥 ,即上面的MD5_KEY
    :return: 字符串
    注意:签名是需要将所有的请求的参赛参与计算,空值不参与计算
    """
    data = {}
    for k in sorted(data_dict.keys()):  # 遍历字典参数名ASCII字典序排序后的key
        v = data_dict.get(k)  # 取出字典中key对应的value
        if type(v) == list:  # 添加XML标记
            v = '![CDATA[{}]]'.format(v)
        data[k] = v
    params_list = sorted(data.items(), key=lambda e: e[0], reverse=False)  # 参数字典参数名ASCII字典序排序为列表
    params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + MD5_KEY  # 组织参数字符串并在末尾添加商户交易密钥
    md5 = hashlib.md5()  # 使用MD5加密模式
    md5.update(params_str.encode('utf-8'))  # 将参数字符串传入
    sign = md5.hexdigest().upper()  # 完成加密并转为大写
    return sign

(字典转XML)

def trans_dict_to_xml(data_dict):
    """
    定义字典转XML的函数
    :param data_dict:
    :return:
    """
    data_xml = []
    for k in data_dict.keys():  # 遍历字典的key
        v = data_dict.get(k)  # 取出字典中key对应的value
        if type(v) == list:  # 添加XML标记
            v = '![CDATA[{}]]'.format(v)
        data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
    return '<xml>{}</xml>'.format(''.join(data_xml))  # 返回XML

(获取本机ip)

def get_ip():
    # 获取当前ip
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(('1.1.1.1', 80))
    ip = s.getsockname()[0]
    s.close()
    return ip

(查询订单)

def query_tool(json_data):
    """
    查询
    """
    try:
        # 必带参数
        data = {
            "service": "unified.trade.query",  # 接口类型
            "mch_id": MCH_ID,  # 门店编号
            "nonce_str": random_str(),  # 随机字符串
            "out_trade_no": json_data["out_trade_no"]  # 商户订单号
        }
        sign = get_sign(data)  # 生成签名
        data['sign'] = sign  # 必带参数中添加签名
        xml_str = trans_dict_to_xml(data)  # 字典转换xml
        res = requests.request('post', "https://pay.hstypay.com/v2/pay/gateway", data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))
        return result
    except Exception as e:
        raise e

2、查询订单(方法调用的是上面的查询方法)

@app.route('/Query', methods=['GET', 'POST'])
def query():
  # 查询
  try:
      form_data = flask.request.get_data()  # 获取未经处理过的原始数据而不管内容类型
      json_data = json.loads(form_data.decode('utf-8'))  # 字符串转化为字典
      result = query_tool(json_data)
      return result
  except Exception as e:
      print(e)
      raise e

3、撤销订单

@app.route('/Revoke', methods=['GET', 'POST'])
def revoke():
    # 撤销
    try:
        form_data = flask.request.get_data()  # 获取到请求带的信息
        json_data = json.loads(form_data.decode('utf-8'))  # 转为json格式
        result = revoke_tool(json_data)
        return result
    except Exception as e:
        print(e)
        raise e

(撤销订单方法)

def revoke_tool(json_data):
    """
    撤销订单
    """
    url = "https://pay.hstypay.com/v2/pay/gateway"  # 撤销请求接口
    try:
        # 必带参数
        data = {
            "service": "unified.micropay.reverse",
            "mch_id": MCH_ID,
            "out_trade_no": json_data['out_trade_no'],
            "nonce_str": random_str(),
            }
        sign = get_sign(data)  # 生成签名
        data['sign'] = sign  # 必带参数中添加签名
        xml_str = trans_dict_to_xml(data)  # 字典转换xml
        res = requests.request('post', url, data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))  # 将xml数据转为python中的dict字典数据
        return result
    except Exception as e:
        raise e

4、退款

@app.route('/Refund', methods=['GET', 'POST'])
def refund():
    # 退款
    try:
        url = 'https://pay.hstypay.com/v2/pay/gateway'
        form_data = flask.request.get_data()  # 获取到请求带的信息
        json_data = json.loads(form_data.decode('utf-8'))  # 转为json格式
        data = {
            "service": "unified.trade.refund",  # 接口类型
            "mch_id": MCH_ID,  # 门店编号
            "out_trade_no": json_data["out_trade_no"],  # 订单号
            "out_refund_no": json_data["out_refund_no"],  # 商户退款单号
            "total_fee": json_data["total_fee"],  # 总金额
            "refund_fee": json_data["refund_fee"],  # 退款金额
            "op_user_id": json_data["op_user_id"],  # 操作员
            "nonce_str": random_str(),  # 随机字符串
            "body": json_data["body"]  # 退款原因
        }  # 必带参数

        sign = get_sign(data)  # 生成签名
        data['sign'] = sign  # 必带参数中添加签名
        xml_str = trans_dict_to_xml(data)  # 字典转换xml
        res = requests.request('post', url, data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))  # 将xml数据转为python中的dict字典数据
        print(result)
        if result['xml']['result_code'] == 0:
            result = query_refund_tool(data)
            return result
        else:
            return result

    except Exception as e:
        raise e

5、退款查询

@app.route('/QueryRefund', methods=['GET', 'POST'])
def query_refund():
    # 退款查询
    try:
        form_data = flask.request.get_data()  # 获取到请求带的信息
        json_data = json.loads(form_data.decode('utf-8'))  # 转为json格式
        result = query_refund_tool(json_data)
        return result
    except Exception as e:
        raise e

(退款查询方法)

def query_refund_tool(json_data):
    """
    查询退款
    """
    url = "https://pay.hstypay.com/v2/pay/gateway"  # 退款请求接口
    try:
        # 必带参数
        data = {
            "service": "unified.trade.refundquery",
            "mch_id": MCH_ID,
            "out_trade_no": json_data["out_trade_no"],
            "out_refund_no": json_data["out_refund_no"],
            "nonce_str": random_str(),  # 随机字符串
            }
        sign = get_sign(data)
        data['sign'] = sign
        xml_str = trans_dict_to_xml(data)
        res = requests.request('post', url, data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))
        return result

    except Exception as e:
        raise e

备注:如果看晕了 可以直接拷贝下面的整体
因为我就只写了2个脚本,1个用于跑主代码、1个跑工具
pay.py(跑主要代码的)

import time

import flask
from flask import Flask

from tool import *

app = Flask(__name__)


@app.route('/Pay', methods=['GET', 'POST'])
def gello_world():
    # 提交付款码支付API
    url = 'https://pay.hstypay.com/v2/pay/gateway'
    try:
        form_data = flask.request.get_data()  # 获取未经处理过的原始数据而不管内容类型
        json_data = json.loads(form_data.decode('utf-8'))  # 字符串转化为字典
        for i in ('service', 'mch_id', 'out_trade_no', 'body', 'total_fee', 'mch_create_ip', 'auth_code'):
            if i not in json_data.keys():
                # 将没有指定参添加上
                json_data[i] = None
        # 获取请求参数,并增加必带参数
        data = {
            "service": "unified.trade.micropay",  # 接口类型
            "mch_id": MCH_ID,  # 门店编号
            "out_trade_no": json_data["out_trade_no"],  # 商户订单号
            "body": json_data["body"],  # 商品描述
            "total_fee": json_data["total_fee"],  # 总金额
            "mch_create_ip": get_ip(),  # 终端IP
            "auth_code": json_data["auth_code"],  # 授权码
            "nonce_str": random_str()  # 随机字符串
        }

        sign = get_sign(data)  # 生成签名
        data["sign"] = sign  # 请求的参数中添加签名
        xml_str = trans_dict_to_xml(data)  # 字典转换xml
        res = requests.request('post', url, data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))  # 将xml数据转为python中的dict字典数据
        try:
            if result['xml']['err_code'] == 'USERPAYING':  # 需要输入密码的情况
                # 然后开始查询
                for i in range(6):
                    print(i+1, '次')
                    time.sleep(5)
                    rest = query_tool(data)
                    if i != 5 and rest['xml']['trade_state'] != 'SUCCESS':
                        continue
                    elif rest['xml']['trade_state'] == 'SUCCESS':
                        print('成功支付', rest)
                        result = query_tool(data)
                        result['xml']['pay_code'] = "支付成功"
                        return result
                    elif rest['xml']['trade_state'] != 'SUCCESS' and i == 5:  # 需要输入密码的情况
                        revoke_tool(data)  # 调用撤销接口
                        result = query_tool(data)
                        return result
                    else:
                        result = query_tool(data)
                        return result
            else:
                return result

        except:
            return result

    except Exception as e:
        print(e)
        raise e


@app.route('/Query', methods=['GET', 'POST'])
def query():
    # 查询
    try:
        form_data = flask.request.get_data()  # 获取未经处理过的原始数据而不管内容类型
        json_data = json.loads(form_data.decode('utf-8'))  # 字符串转化为字典
        result = query_tool(json_data)
        return result
    except Exception as e:
        print(e)
        raise e


@app.route('/Revoke', methods=['GET', 'POST'])
def revoke():
    # 撤销
    try:
        form_data = flask.request.get_data()  # 获取到请求带的信息
        json_data = json.loads(form_data.decode('utf-8'))  # 转为json格式
        result = revoke_tool(json_data)
        return result
    except Exception as e:
        print(e)
        raise e


@app.route('/Refund', methods=['GET', 'POST'])
def refund():
    # 退款
    try:
        url = 'https://pay.hstypay.com/v2/pay/gateway'
        form_data = flask.request.get_data()  # 获取到请求带的信息
        json_data = json.loads(form_data.decode('utf-8'))  # 转为json格式
        data = {
            "service": "unified.trade.refund",  # 接口类型
            "mch_id": MCH_ID,  # 门店编号
            "out_trade_no": json_data["out_trade_no"],  # 订单号
            "out_refund_no": json_data["out_refund_no"],  # 商户退款单号
            "total_fee": json_data["total_fee"],  # 总金额
            "refund_fee": json_data["refund_fee"],  # 退款金额
            "op_user_id": json_data["op_user_id"],  # 操作员
            "nonce_str": random_str(),  # 随机字符串
            "body": json_data["body"]  # 退款原因
        }  # 必带参数

        sign = get_sign(data)  # 生成签名
        data['sign'] = sign  # 必带参数中添加签名
        xml_str = trans_dict_to_xml(data)  # 字典转换xml
        res = requests.request('post', url, data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))  # 将xml数据转为python中的dict字典数据
        print(result)
        if result['xml']['result_code'] == 0:
            result = query_refund_tool(data)
            return result
        else:
            return result

    except Exception as e:
        raise e


@app.route('/QueryRefund', methods=['GET', 'POST'])
def query_refund():
    # 退款查询
    try:
        form_data = flask.request.get_data()  # 获取到请求带的信息
        json_data = json.loads(form_data.decode('utf-8'))  # 转为json格式
        result = query_refund_tool(json_data)
        return result
    except Exception as e:
        raise e

if __name__ == '__main__':
    app.run()

tools.py(跑工具的)

import hashlib
import json
import os
import socket
from collections import defaultdict
from random import Random
from urllib import parse

import xmltodict

import requests
import OpenSSL


def get_configuration_info():
    """
    获取前置机账户配置
    """
    url = "http://******"
    Port = "4013"
    CpnID = "001111"
    res = requests.request('post', url, data={"Port": Port, "CpnID": CpnID})
    result = json.loads(res.content)
    result["data"] = json.loads(result["data"])
    aws_s3_url = result["data"]["cpnActMchinRcd"][0]["ActCfg"]
    res = requests.request('GET', aws_s3_url)
    aws_str = str(res.content)
    awx_json = parse.unquote(aws_str)
    for a in json.loads(awx_json[2:-1]):
        if a["Keyname"] == "mch_id":
            MCH_ID = a["Keyval"]
        elif a["Keyname"] == "key":
            MD5_KEY = a["Keyval"]
    return {'MCH_ID': MCH_ID, 'MD5_KEY': MD5_KEY}


MCH_ID = get_configuration_info()['MCH_ID']  # mch_id
MD5_KEY = get_configuration_info()['MD5_KEY']  # MD5密钥


def random_str(randomlength=16):
    """
    生成随机字符串
    :param randomlength: 字符串长度
    :return:
    """
    strs = ''
    chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
    length = len(chars) - 1
    random = Random()
    for i in range(randomlength):
        strs += chars[random.randint(0, length)]
    return strs


def get_sign(data_dict):
    """
    签名函数
    :param data_dict: 需要签名的参数,格式为字典
    :param key: 密钥 ,即上面的MD5_KEY
    :return: 字符串
    注意:签名是需要将所有的请求的参赛参与计算,空值不参与计算
    """
    data = {}
    for k in sorted(data_dict.keys()):  # 遍历字典参数名ASCII字典序排序后的key
        v = data_dict.get(k)  # 取出字典中key对应的value
        if type(v) == list:  # 添加XML标记
            v = '![CDATA[{}]]'.format(v)
        data[k] = v
    params_list = sorted(data.items(), key=lambda e: e[0], reverse=False)  # 参数字典参数名ASCII字典序排序为列表
    params_str = "&".join(u"{}={}".format(k, v) for k, v in params_list) + '&key=' + MD5_KEY  # 组织参数字符串并在末尾添加商户交易密钥
    md5 = hashlib.md5()  # 使用MD5加密模式
    md5.update(params_str.encode('utf-8'))  # 将参数字符串传入
    sign = md5.hexdigest().upper()  # 完成加密并转为大写
    return sign


def trans_dict_to_xml(data_dict):
    """
    定义字典转XML的函数
    :param data_dict:
    :return:
    """
    data_xml = []
    for k in data_dict.keys():  # 遍历字典的key
        v = data_dict.get(k)  # 取出字典中key对应的value
        if type(v) == list:  # 添加XML标记
            v = '![CDATA[{}]]'.format(v)
        data_xml.append('<{key}>{value}</{key}>'.format(key=k, value=v))
    return '<xml>{}</xml>'.format(''.join(data_xml))  # 返回XML


def query_tool(json_data):
    """
    查询
    """
    try:
        # 必带参数
        data = {
            "service": "unified.trade.query",  # 接口类型
            "mch_id": MCH_ID,  # 门店编号
            "nonce_str": random_str(),  # 随机字符串
            "out_trade_no": json_data["out_trade_no"]  # 商户订单号
        }
        sign = get_sign(data)  # 生成签名
        data['sign'] = sign  # 必带参数中添加签名
        xml_str = trans_dict_to_xml(data)  # 字典转换xml
        res = requests.request('post', "https://pay.hstypay.com/v2/pay/gateway", data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))
        return result
    except Exception as e:
        raise e


def query_refund_tool(json_data):
    """
    查询退款
    """
    url = "https://pay.hstypay.com/v2/pay/gateway"  # 退款请求接口
    try:
        # 必带参数
        data = {
            "service": "unified.trade.refundquery",
            "mch_id": MCH_ID,
            "out_trade_no": json_data["out_trade_no"],
            "out_refund_no": json_data["out_refund_no"],
            "nonce_str": random_str(),  # 随机字符串
            }
        sign = get_sign(data)
        data['sign'] = sign
        xml_str = trans_dict_to_xml(data)
        res = requests.request('post', url, data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))
        return result

    except Exception as e:
        raise e


def revoke_tool(json_data):
    """
    撤销订单
    """
    url = "https://pay.hstypay.com/v2/pay/gateway"  # 撤销请求接口
    try:
        # 必带参数
        data = {
            "service": "unified.micropay.reverse",
            "mch_id": MCH_ID,
            "out_trade_no": json_data['out_trade_no'],
            "nonce_str": random_str(),
            }
        sign = get_sign(data)  # 生成签名
        data['sign'] = sign  # 必带参数中添加签名
        xml_str = trans_dict_to_xml(data)  # 字典转换xml
        res = requests.request('post', url, data=xml_str.encode())  # 以POST方式向微信公众平台服务器发起请求
        result = json.loads(json.dumps(xmltodict.parse(res.content)))  # 将xml数据转为python中的dict字典数据
        return result
    except Exception as e:
        raise e


def get_ip():
    # 获取当前ip
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.connect(('1.1.1.1', 80))
    ip = s.getsockname()[0]
    s.close()
    return ip




相关文章

  • 接入威富通聚合支付平台

    开发文档:https://open.swiftpass.cn/openapi?code=hsty[https://...

  • Session1+Session2作业【通莞股份】

    十四天营销训练营作业 张翼翔 公司/团队/项目名称:通莞股份/聚合支付事业部/聚合支付平台 产品名称:聚合支付平台...

  • 聚合支付代理实时到账无上限-掌柜买单

    移动扫码支付平台的强大功能 一、接入聚合支付:提高门店营业员收银效率,节省消费者支付时间。 二、支付即营销:支付即...

  • 聚合支付平台有哪些?

    聚合支付平台有哪些?聚合支付平台有很多,看你怎么选择合作方,正规的聚合支付平台都是只提供服务不碰结算资金,聚合平台...

  • 郑州沃盟:聚合支付火爆的原因?了解一下,惠智联

    什么是聚合支付? 聚合支付是惠智联为商户打造的一站式接入的钱包支付支付宝支付,微信支付,京东支付,信用卡支付,银行...

  • 2019-07-17

    支付系统 三方支付 京东支付 银联支付 [建行龙支付] 招商一网通 聚合支付 1.什么是聚合支付 2.有名的聚合支...

  • 聚合支付浅析

    一、什么是聚合支付 聚合支付,又称第四方支付平台,把多家第三方支付提供的支付接口聚合到一个平台上面,来给商家或者个...

  • 躺着赚钱的IT业务点击进来就是金子

    最新聚合支付源码,支持支付宝,微信,网银,财付通,全渠道支付,其他第三方支付通道,完全开源, 源码包括平台主站,商...

  • 聚合支付平台,微信/支付宝支付

    不多说,推荐个自己使用的聚合支付平台。 小微聚合支付平台 官方网站:https://weidoufu.com[ht...

  • 聚合支付也可以是份兼职

    聚合支付也可以是份兼职 聚合支付是基于第三方支付平台的拓展项目,是整合市面上其他支付平台的移动支付新概念,也是在第...

网友评论

      本文标题:接入威富通聚合支付平台

      本文链接:https://www.haomeiwen.com/subject/cxhzsltx.html