微信JSAPI支付结果通知(代码详解)

支付结果通知官方文档

## 应用场景
支付完成后,微信会把相关支付结果及用户信息通过数据流的形式发送给商户,商户需要接收处理,并按文档规范返回应答。

注意:

1、同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。

2、后台通知交互时,如果微信收到商户的应答不符合规范或超时,微信会判定本次通知失败,重新发送通知,直到成功为止(在通知一直不成功的情况下,微信总共会发起多次通知,通知频率为15s/15s/30s/3m/10m/20m/30m/30m/30m/60m/3h/3h/3h/6h/6h

  • 总计 24h4m),但微信不保证通知最终一定能成功。

3、在订单状态不明或者没有收到微信支付结果通知的情况下,建议商户主动调用微信支付【查询订单API】确认订单状态。

特别提醒:

1、商户系统对于支付结果通知的内容一定要做签名验证,并校验返回的订单金额是否与商户侧的订单金额一致,防止数据泄漏导致出现“假通知”,造成资金损失。

2、当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

接口链接

我们在统一下单接口中设置的notify_url,当用户支付成功后,微信将把支付结果及一些用户数据和交易数据发送到这个借口,而我们后台就必须正确的接收处理这些数据,并按文档规范返回应答.

相应的通知参数请各位移步到官方文档观看,我在这就不啰嗦了

直接贴上我的代码:

class WechatNotifyUrl(View):
    '''
    支付完成后,微信会把相关支付结果及用户信息通过数据流的形式发送给商户,商户需要接收处理,并按文档规范返回应答。
    详情参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
    发给商户的参数:
    <xml>
        <appid><![CDATA[wx2421b1c4370ec43b]]></appid>
        <attach><![CDATA[支付测试]]></attach>
        <bank_type><![CDATA[CFT]]></bank_type>
        <fee_type><![CDATA[CNY]]></fee_type>
        <is_subscribe><![CDATA[Y]]></is_subscribe>
        <mch_id><![CDATA[10000100]]></mch_id>
        <nonce_str><![CDATA[5d2b6c2a8db53831f7eda20af46e531c]]></nonce_str>
        <openid><![CDATA[oUpF8uMEb4qRXf22hE3X68TekukE]]></openid>
        <out_trade_no><![CDATA[1409811653]]></out_trade_no>
        <result_code><![CDATA[SUCCESS]]></result_code>
        <return_code><![CDATA[SUCCESS]]></return_code>
        <sign><![CDATA[B552ED6B279343CB493C5DD0D78AB241]]></sign>
        <time_end><![CDATA[20140903131540]]></time_end>
        <total_fee>1</total_fee>
        <coupon_fee><![CDATA[10]]></coupon_fee>
        <coupon_count><![CDATA[1]]></coupon_count>
        <coupon_type><![CDATA[CASH]]></coupon_type>
        <coupon_id><![CDATA[10000]]></coupon_id>
        <coupon_fee><![CDATA[100]]></coupon_fee>
        <trade_type><![CDATA[JSAPI]]></trade_type>
        <transaction_id><![CDATA[1004400740201409030005092168]]></transaction_id>
    </xml>
    返回给微信的参数
    <xml>
        <return_code><![CDATA[SUCCESS]]></return_code>
        <return_msg><![CDATA[OK]]></return_msg>
    </xml>
    '''
    def post(self,request):
        return_data = '''
        <xml>
            <return_code><![CDATA[{return_code}]]></return_code>
            <return_msg><![CDATA[{return_msg}]]></return_msg>
        </xml>
        '''
        # 获取到微信发送过来的数据
        result = request.body.decode()
        ret = dict_parse_from_xml(result)
        # 如果return_code返回的是FAIL,说明返回通信标识失败
        return_code = ret.get('return_code','FAIL')
        if return_code == 'FAIL':
            # 将数据转换成为xml,返回
            logger.info('微信支付礼物结果通知商户,返回的标识信息为FAIL')
            return_msg = ret['return_msg']
            msg = {'return_code':'FAIL','return_msg':return_msg}
            return_data = return_data.format(**msg)
            return HttpResponse(return_data,content_type="text/xml")
        # 支付的结果
        result_code = ret.get('result_code','FAIL')
        logger.info('pay result is {}'.format(result_code))
        if return_code == 'SUCCESS' and result_code == 'SUCCESS':
            # 支付完成的情况
            # 获取到商户的订单号,查找到当前的预支付对象(记录)
            out_trade_no = ret.get('out_trade_no')
            try:
                order = PaymentOrder.objects.get(charge_id=out_trade_no)
                # 签名验证,并校验返回的订单金额是否与商户侧的订单金额一致
                wechart_sign = ret.get('sign',None)
                # 计算签名时,签名不能计算在内
                del ret['sign']
                sign,_ = get_sign(ret,pay_sign_key=settings.WECHAT_API_KEY)
                money = ret.get('total_fee')
                total_fee = float(int(money)/100)
                amount = float(order.amount)
                if sign != wechart_sign and amount != total_fee:
                    logger.info("签名或金额不对应")
                    raise Exception('签名或金额不对应')
            except:
                logger.info('没有此预付订单')
                return HttpResponse('没有此预付订单')
            else:
                # 当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。
                pay_status = order.status
                logger.info('pay_status is {}'.format(pay_status))
                if pay_status == PAYMENT_ORDER_STATUS_FINISHED:
                    logger.info("Order {} already {}".format(order.charge_id, order.status))
                if pay_status == PAYMENT_ORDER_STATUS_PENDING:
                    # transaction_id    微信支付订单号
                    transaction_id = ret.get('transaction_id')
                    order.status = PAYMENT_ORDER_STATUS_PAID
                    order.transaction_id = transaction_id
                    order.save()
                    # 源头账户为微信支付主账户
                    source_account = get_wechat_account()
                    # 目的地账户为关联到预支付订单的账户
                    destination_account = order.account
                    # 资金从源头账户转移到目的地账户
                    logger.info("Transfer of {} from account {} to account {}".format(
                        order.amount, source_account, destination_account))
                    merchant = settings.ACCOUNT_MERCHANT_WECHAT_PREFIX
                    transfer = Transfer.objects.create(
                        source_account, destination_account, order.amount,
                        order.user, merchant, order.description)

                    order.transfer = transfer
                    order.status = PAYMENT_ORDER_STATUS_FINISHED
                    order.save()
                    # 购买课程信息/打赏红包/礼物等信息存储入库
                    charge(order.charge_id, order, destination_account)
                return_msg = {'return_code':'SUCCESS','return_msg':'ok'}
                return_data = return_data.format(**return_msg)
                logger.info('回复微信支付通知成功')
                return HttpResponse(return_data,content_type="text/xml")
        else:
            # result_code 为FAIL时返回错误码
            err_code_des = ret.get('err_code_des')
            logger.info('支付失败的原因是:{}'.format(err_code_des))
            err_code = ret.get('err_code')
            return_msg = {'return_code':'FAIL','return_msg':err_code}
            return_data = return_data.format(**return_msg)
            return HttpResponse(return_data,content_type="text/xml")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值