wechatcashout.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. # coding=utf-8
  2. import uuid
  3. import os
  4. import requests
  5. import json
  6. import xmltodict
  7. import time
  8. from hashlib import md5
  9. from django.conf import settings
  10. from utils.exceptions import CustomError
  11. class WechatTenantPay():
  12. def __init__(self, appid, mch_id, partner_trade_no, openid, amount, merchant_key, cert, key):
  13. self.params = {
  14. 'mch_appid': appid, # 申请商户号的appid或商户号绑定的appid
  15. 'mchid': mch_id, # 微信支付分配的商户号
  16. 'nonce_str': generate_nonce_str(), # 随机字符串,不长于32位
  17. 'partner_trade_no': partner_trade_no, # 商户订单号,需保持唯一性
  18. 'openid': openid, # 商户appid下,某用户的openid
  19. 'check_name': 'NO_CHECK', # 校验用户姓名选项
  20. 'amount': amount, # 金额 企业付款金额 单位为分
  21. 'desc': u'佣金', # 企业付款备注
  22. }
  23. self.params['sign'] = generate_sign(self.params, merchant_key)
  24. self.url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers'
  25. self.cert_file = cert
  26. self.cert_key = key
  27. def pay(self):
  28. result = send_cert_request(self.url, self.params, self.cert_file, self.cert_key)
  29. return result
  30. class PayQuery():
  31. def __init__(self, partner_trade_no, mch_id, appid, merchant_key, cert, key):
  32. self.url = 'https://api.mch.weixin.qq.com/mmpaymkttransfers/gettransferinfo'
  33. self.cert_file = cert
  34. self.cert_key = key
  35. self.params = {
  36. 'nonce_str': generate_nonce_str(),
  37. 'partner_trade_no': partner_trade_no,
  38. 'mch_id': mch_id,
  39. 'appid': appid,
  40. }
  41. self.params['sign'] = generate_sign(self.params, merchant_key)
  42. def query(self):
  43. result = send_cert_request(self.url, self.params, self.cert_file, self.cert_key)
  44. return result
  45. def send_cert_request(url, param, cert_file, cert_key):
  46. '''
  47. 发送携带证书的xml请求
  48. '''
  49. xml = xmltodict.unparse({'root': param})
  50. response = requests.post(url, data=xml.encode('utf-8'), headers={'Content-Type': 'text/xml'}, cert=(cert_file, cert_key), verify=False)
  51. xmlmsg = json.loads(json.dumps(xmltodict.parse(response.content)))['xml']
  52. print(xmlmsg)
  53. return xmlmsg
  54. def generate_nonce_str():
  55. """
  56. 生成随机字符串
  57. """
  58. return str(uuid.uuid4()).replace('-', '')
  59. def generate_sign(params, merchant_key):
  60. """
  61. 生成md5签名的参数
  62. """
  63. if 'sign' in params:
  64. params.pop('sign')
  65. src = '&'.join(['%s=%s' % (k, v) for k, v in sorted(params.items())]) + '&key=%s' % merchant_key
  66. return md5(src.encode('utf-8')).hexdigest().upper()
  67. def validate_sign(resp_dict, merchant_key):
  68. """
  69. 验证微信返回的签名
  70. """
  71. if 'sign' not in resp_dict:
  72. return False
  73. wx_sign = resp_dict['sign']
  74. sign = generate_sign(resp_dict, merchant_key)
  75. if sign == wx_sign:
  76. return True
  77. return False
  78. def generate_response_data(resp_dict):
  79. """
  80. 字典转xml
  81. """
  82. return xmltodict.unparse({'xml': resp_dict}, pretty=True, full_document=False).encode('utf-8')