支付结果通知官方文档
## 应用场景
支付完成后,微信会把相关支付结果及用户信息通过数据流的形式发送给商户,商户需要接收处理,并按文档规范返回应答。
注意:
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")