微信小程序之退款功能实现---python

官方所需的必备参数:

字段名 变量名 必填 类型 示例值 描述
小程序ID appid String(32) wx8888888888888888 微信分配的小程序ID
商户号 mch_id String(32) 1900000109 微信支付分配的商户号
随机字符串 nonce_str String(32) 5K8264ILTKCH16CQ2502SI8ZNMTM67VS 随机字符串,不长于32位。推荐随机数生成算法
签名 sign String(32) C380BEC2BFD727A4B6845133519F3AD6 签名,详见签名生成算法签名生成算法
签名类型 sign_type String(32) HMAC-SHA256 签名类型,目前支持HMAC-SHA256和MD5,默认为MD5
微信订单号 transaction_id 二选一 String(32) 1217752501201407033233368018 微信生成的订单号,在支付通知中有返回
商户订单号 out_trade_no String(32) 1217752501201407033233368018 商户系统内部订单号,要求32个字符内,只能是数字、大小写字母_-*@ ,且在同一个商户号下唯一。transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no
商户退款单号 out_refund_no String(64) 1217752501201407033233368018 商户系统内部的退款单号,商户系统内部唯一,只能是数字、大小写字母_-*@ ,同一退款单号多次请求只退一笔。
订单金额 total_fee Int 100 订单总金额, 单位为分, 只能为整数,详见支付金额
退款金额 refund_fee Int 100 退款总金额,订单总金额,单位为分,只能为整数,详见支付金额
货币种类 refund_fee_type String(8) CNY 货币类型,符合ISO 4217标准的三位字母代码,默认人民币:CNY,其他值列表详见货币类型
退款原因 refund_desc String(80) 商品已售完 若商户传入,会在下发给用户的退款消息中体现退款原因注意:若订单退款金额≤1元,且属于部分退款,则不会在退款消息中体现退款原因
退款资金来源 refund_account String(30) REFUND_SOURCE_RECHARGE_FUNDS仅针对老资金流商户使用REFUND_SOURCE_UNSETTLED_FUNDS—未结算资金退款(默认使用未结算资金退款)REFUND_SOURCE_RECHARGE_FUNDS—可用余额退款
退款结果通知url notify_url String(256) https://weixin.qq.com/notify/ 异步接收微信支付退款结果通知的回调地址,通知URL必须为外网可访问的url,不允许带参数如果参数中传了notify_url,则商户平台上配置的回调地址将不会生效。

XML举例如下:


   wx2421b1c4370ec43b
   10000100
   6cefdb308e1e2e8aabd48cf79e546a02
   1415701182
   1415757673
   1
   1
   
   FE56DD4AA85C0EECA82C35595A69E153

直接贴demo :


# 请求退款地址
refundUrl = 'https://api.mch.weixin.qq.com/secapi/pay/refund'
# 创建小程序对象, 这些东西都是需要事先准备好的,这个是支付用的
# wxrpay = WXAppPay ( appid=APP_ID, mch_id=APP_MCH_ID, partner_key=APP_PARTNER_KEY )

class RefundUrl ( APIView ):
    def post ( self, request ):
        out_refund_no = request.POST[ 'out_refund_no' ]  # 退款单号
        total_fee = request.POST['total_fee']  # 订单金额
        out_trade_no = request.POST[ 'out_trade_no' ] # 订单号
        refund_fee = request.POST[ 'refund_fee' ]  # 退款金额
        nonce_str = WXUtils.randomStr ()  # 随机32位字符串
        prepay = dict ()
        # params : 都是调用微信退款接口必填的参数
        params = {
            'appid': APP_ID,
            'mch_id': APP_MCH_ID,
            # 'notify_url': "https://www.****.com/refund/", 退款回调地址
            'nonce_str': nonce_str,
            'out_trade_no': out_trade_no,
            'out_refund_no': out_refund_no,
            'refund_fee': int ( float ( refund_fee ) * 100 ),
            'sign_type': 'MD5',
            'total_fee': int ( float ( total_fee ) * 100 )
        }
        #  sign : MD5 的加密签证
        sign = WXUtils.wx_sign ( params )
        # 加密完之后,放入params 进行请求
        params[ 'sign' ] = sign
        xmljson = WXUtils.send_xml_request ( refundUrl, params )
        mes = dict ()
        # 这里呢 我没有用回调地址, 而是直接在这里进行成功和失败判断.
        if xmljson[ 'xml' ][ 'return_code' ] == 'SUCCESS':
            if "err_code" not in xmljson[ 'xml' ]:
                # 微信订单号
                prepay[ 'transaction_id' ] = xmljson[ 'xml' ][ 'transaction_id' ]
                # 商户订单号
                prepay[ 'out_trade_no' ] = xmljson[ 'xml' ][ 'out_trade_no' ]
                # 商户退款单号
                prepay[ 'out_refund_no' ] = xmljson[ 'xml' ][ 'out_refund_no' ]
                # 微信退款单号
                prepay[ 'refund_id' ] = xmljson[ 'xml' ][ 'refund_id' ]
                # 退款总金额,单位为分,可以做部分退款
                prepay[ 'refund_fee' ] = xmljson[ 'xml' ][ 'refund_fee' ]
                # 订单总金额,单位为分,只能为整数
                prepay[ 'total_fee' ] = xmljson[ 'xml' ][ 'total_fee' ]

                logger.info ( {"退单号: {}-退款成功,操作人员: {}, 操作时间: {}".format ( xmljson[ 'xml' ][ 'out_refund_no' ] ,'某某某',
                               now_time) } )
				# __可以在这里直接写你的实际操作业务逻辑...
            else:
                # 错误代码
                mes[ 'code' ] = xmljson[ 'xml' ][ 'err_code' ]
                # 错误代码描述
                mes[ 'desc' ] = xmljson[ 'xml' ][ 'err_code_des' ]

        else:
            mes[ 'code' ] = '500'
            mes[ 'desc' ] = '提交业务失败'
        return Response ( prepay )


class WXUtils ( object ):
    """关于微信支付的小工具"""

    # 随机32位字符串
    @staticmethod
    def randomStr ():
        return ''.join ( random.sample ( string.ascii_letters + string.digits, 32 ) )

    # 微信签名算法函数
    @staticmethod
    def wx_sign ( param ):
        stringA = ""
        ks = sorted ( param.keys () )
        # 排序
        for k in ks:
            stringA += (k + "=" + str ( param[ k ] ) + "&")
        # 拼接商户key
        stringSignTemp = stringA + 'key=' + APP_PARTNER_KEY
        # md5加密
        hash_md5 = hashlib.md5 ( stringSignTemp.encode ( 'utf-8' ) )
        sign = hash_md5.hexdigest ().upper ()
        print ( sign )
        return sign

    # 发送xml请求
    @staticmethod
    def send_xml_request ( url, param ):
        import os
        param = {'xml': param}
        xml = xmltodict.unparse ( param )
        # cert  里面的是证书, 没有证书, 请求会失败的, 具体证书怎么来请看微信开发文档.
        response = requests.post ( url, data=xml.encode ( "utf-8" ), cert=(
            r'地址\apiclient_cert.pem',
            r'地址\apiclient_key.pem'),
                                   headers={"Content-Type": "charset=utf-8"} )
        msg = response.content
        xmlmsg = xmltodict.parse ( msg )
        return xmlmsg


微信退款–官方文档
最简单的退款, 不喜勿喷,若有不妥之处, 还望支出, 大家共同学习!

你可能感兴趣的:(python)