|
@@ -5,6 +5,8 @@ from urllib.parse import quote
|
|
|
import requests
|
|
|
import xmltodict
|
|
|
|
|
|
+from Ansjer.config import BASE_DIR
|
|
|
+
|
|
|
|
|
|
class WechatPayObject:
|
|
|
"""配置账号信息"""
|
|
@@ -20,6 +22,7 @@ class WechatPayObject:
|
|
|
self.TRADE_TYPE = 'APP'
|
|
|
self.APIKEY = 'ZHansjeransjeransjer680301000000'
|
|
|
self.url = 'https://api.mch.weixin.qq.com/pay/unifiedorder' # 微信请求url
|
|
|
+ self.refund_url = 'https://api.mch.weixin.qq.com/secapi/pay/refund' # 退款url
|
|
|
self.error = None
|
|
|
self.params = None
|
|
|
|
|
@@ -199,3 +202,27 @@ class WechatPayObject:
|
|
|
xml += '<' + k + '>' + v + '</' + k + '>'
|
|
|
xml += "</xml>"
|
|
|
return xml
|
|
|
+
|
|
|
+ def refund(self, out_trade_no, out_refund_no, total_fee, refund_fee):
|
|
|
+ params = {
|
|
|
+ 'appid': self.APPID,
|
|
|
+ 'mch_id': self.MCHID,
|
|
|
+ 'nonce_str': self.getNonceStr(),
|
|
|
+ 'out_trade_no': out_trade_no, # 商户订单号
|
|
|
+ 'out_refund_no': out_refund_no, # 商户退款单号
|
|
|
+ 'total_fee': total_fee, # 订单金额
|
|
|
+ 'refund_fee': refund_fee # 退款金额
|
|
|
+ }
|
|
|
+ # doc: https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=4_3
|
|
|
+ string_sign = "&".join(['{}={}'.format(k, params[k]) for k in sorted(params)] + ['key={}'.format(self.APIKEY)])
|
|
|
+ params['sign'] = hashlib.md5(string_sign.encode('utf8')).hexdigest().upper() # MD5签名
|
|
|
+ xml = "<xml>{}</xml>".format("".join(['<{k}>{v}</{k}>'.format(k=k, v=v) for k, v in params.items()])) # 数据拼接成xml格式
|
|
|
+ cert = '{}/Ansjer/file/wechatpay/apiclient_cert.pem'.format(BASE_DIR)
|
|
|
+ key = '{}/Ansjer/file/wechatpay/apiclient_key.pem'.format(BASE_DIR)
|
|
|
+ r = requests.post(url=self.refund_url, headers={'Content-Type': 'text/xml'}, data=xml.encode('utf-8'),
|
|
|
+ cert=(cert, key), verify=True)
|
|
|
+ response = xmltodict.parse(r.text)
|
|
|
+ if response['xml']['return_code'] == 'SUCCESS':
|
|
|
+ return True
|
|
|
+ else:
|
|
|
+ return False
|