优化工单模块,增加企微模块
This commit is contained in:
199
sg_wechat_enterprise/we_api/pay/__init__.py
Normal file
199
sg_wechat_enterprise/we_api/pay/__init__.py
Normal file
@@ -0,0 +1,199 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
import sys
|
||||
import inspect
|
||||
import logging
|
||||
|
||||
import requests
|
||||
import xmltodict
|
||||
from xml.parsers.expat import ExpatError
|
||||
from optionaldict import optionaldict
|
||||
|
||||
from wechatpy.utils import random_string
|
||||
from wechatpy.exceptions import WeChatPayException, InvalidSignatureException
|
||||
from wechatpy.pay.utils import (
|
||||
calculate_signature, _check_signature, dict_to_xml
|
||||
)
|
||||
from wechatpy.pay.base import BaseWeChatPayAPI
|
||||
from wechatpy.pay import api
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _is_api_endpoint(obj):
|
||||
return isinstance(obj, BaseWeChatPayAPI)
|
||||
|
||||
|
||||
class WeChatPay(object):
|
||||
"""
|
||||
微信红包接口
|
||||
|
||||
:param appid: 微信公众号 appid
|
||||
:param api_key: 商户 key
|
||||
:param mch_id: 商户号
|
||||
:param sub_mch_id: 可选,子商户号,受理模式下必填
|
||||
:param mch_cert: 必填,商户证书路径
|
||||
:param mch_key: 必填,商户证书私钥路径
|
||||
"""
|
||||
redpack = api.WeChatRedpack()
|
||||
"""红包接口"""
|
||||
transfer = api.WeChatTransfer()
|
||||
"""企业付款接口"""
|
||||
coupon = api.WeChatCoupon()
|
||||
"""代金券接口"""
|
||||
order = api.WeChatOrder()
|
||||
"""订单接口"""
|
||||
refund = api.WeChatRefund()
|
||||
"""退款接口"""
|
||||
micropay = api.WeChatMicroPay()
|
||||
"""刷卡支付接口"""
|
||||
tools = api.WeChatTools()
|
||||
"""工具类接口"""
|
||||
jsapi = api.WeChatJSAPI()
|
||||
|
||||
API_BASE_URL = 'https://api.mch.weixin.qq.com/'
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
self = super(WeChatPay, cls).__new__(cls)
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
import copy
|
||||
# Python 2.6 inspect.gemembers bug workaround
|
||||
# http://bugs.python.org/issue1785
|
||||
for name, _api in self.__class__.__dict__.items():
|
||||
if isinstance(_api, BaseWeChatPayAPI):
|
||||
_api = copy.deepcopy(_api)
|
||||
_api._client = self
|
||||
setattr(self, name, _api)
|
||||
else:
|
||||
api_endpoints = inspect.getmembers(self, _is_api_endpoint)
|
||||
for name, _api in api_endpoints:
|
||||
api_cls = type(_api)
|
||||
_api = api_cls(self)
|
||||
setattr(self, name, _api)
|
||||
return self
|
||||
|
||||
def __init__(self, appid, api_key, mch_id, sub_mch_id=None,
|
||||
mch_cert=None, mch_key=None):
|
||||
"""
|
||||
:param appid: 微信公众号 appid
|
||||
:param api_key: 商户 key
|
||||
:param mch_id: 商户号
|
||||
:param sub_mch_id: 可选,子商户号,受理模式下必填
|
||||
:param mch_cert: 商户证书路径
|
||||
:param mch_key: 商户证书私钥路径
|
||||
"""
|
||||
self.appid = appid
|
||||
self.api_key = api_key
|
||||
self.mch_id = mch_id
|
||||
self.sub_mch_id = sub_mch_id
|
||||
self.mch_cert = mch_cert
|
||||
self.mch_key = mch_key
|
||||
|
||||
def _request(self, method, url_or_endpoint, **kwargs):
|
||||
if not url_or_endpoint.startswith(('http://', 'https://')):
|
||||
api_base_url = kwargs.pop('api_base_url', self.API_BASE_URL)
|
||||
url = '{base}{endpoint}'.format(
|
||||
base=api_base_url,
|
||||
endpoint=url_or_endpoint
|
||||
)
|
||||
else:
|
||||
url = url_or_endpoint
|
||||
|
||||
if isinstance(kwargs.get('data', ''), dict):
|
||||
data = optionaldict(kwargs['data'])
|
||||
if 'mchid' not in data:
|
||||
# Fuck Tencent
|
||||
data.setdefault('mch_id', self.mch_id)
|
||||
data.setdefault('sub_mch_id', self.sub_mch_id)
|
||||
data.setdefault('nonce_str', random_string(32))
|
||||
sign = calculate_signature(data, self.api_key)
|
||||
body = dict_to_xml(data, sign)
|
||||
body = body.encode('utf-8')
|
||||
kwargs['data'] = body
|
||||
|
||||
# 商户证书
|
||||
if self.mch_cert and self.mch_key:
|
||||
kwargs['cert'] = (self.mch_cert, self.mch_key)
|
||||
|
||||
res = requests.request(
|
||||
method=method,
|
||||
url=url,
|
||||
**kwargs
|
||||
)
|
||||
try:
|
||||
res.raise_for_status()
|
||||
except requests.RequestException as reqe:
|
||||
raise WeChatPayException(
|
||||
return_code=None,
|
||||
client=self,
|
||||
request=reqe.request,
|
||||
response=reqe.response
|
||||
)
|
||||
|
||||
return self._handle_result(res)
|
||||
|
||||
def _handle_result(self, res):
|
||||
res.encoding = 'utf-8'
|
||||
xml = res.text
|
||||
try:
|
||||
data = xmltodict.parse(xml)['xml']
|
||||
except (xmltodict.ParsingInterrupted, ExpatError):
|
||||
# 解析 XML 失败
|
||||
logger.debug('WeChat payment result xml parsing error', exc_info=True)
|
||||
return xml
|
||||
|
||||
return_code = data['return_code']
|
||||
return_msg = data.get('return_msg')
|
||||
result_code = data.get('result_code')
|
||||
errcode = data.get('err_code')
|
||||
errmsg = data.get('err_code_des')
|
||||
if return_code != 'SUCCESS' or result_code != 'SUCCESS':
|
||||
# 返回状态码不为成功
|
||||
raise WeChatPayException(
|
||||
return_code,
|
||||
result_code,
|
||||
return_msg,
|
||||
errcode,
|
||||
errmsg,
|
||||
client=self,
|
||||
request=res.request,
|
||||
response=res
|
||||
)
|
||||
return data
|
||||
|
||||
def get(self, url, **kwargs):
|
||||
return self._request(
|
||||
method='get',
|
||||
url_or_endpoint=url,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def post(self, url, **kwargs):
|
||||
return self._request(
|
||||
method='post',
|
||||
url_or_endpoint=url,
|
||||
**kwargs
|
||||
)
|
||||
|
||||
def check_signature(self, params):
|
||||
return _check_signature(params, self.api_key)
|
||||
|
||||
def parse_payment_result(self, xml):
|
||||
"""解析微信支付结果通知"""
|
||||
try:
|
||||
data = xmltodict.parse(xml)
|
||||
except (xmltodict.ParsingInterrupted, ExpatError):
|
||||
raise InvalidSignatureException()
|
||||
|
||||
if not data or 'xml' not in data:
|
||||
raise InvalidSignatureException()
|
||||
|
||||
data = data['xml']
|
||||
sign = data.pop('sign', None)
|
||||
real_sign = calculate_signature(data, self.api_key)
|
||||
if sign != real_sign:
|
||||
raise InvalidSignatureException()
|
||||
|
||||
data['sign'] = sign
|
||||
return data
|
||||
Reference in New Issue
Block a user