官方所需的必备参数:
字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|---|
小程序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
# 请求退款地址
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
微信退款–官方文档
最简单的退款, 不喜勿喷,若有不妥之处, 还望支出, 大家共同学习!