__init__.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import logging
  4. import dicttoxml
  5. import six
  6. from django.utils.module_loading import import_string
  7. from typing import TYPE_CHECKING, Optional, cast, Union
  8. from apilib.systypes import IterConstant
  9. from apps.web.constant import AppPlatformType
  10. if TYPE_CHECKING:
  11. from apps.web.core.models import WechatPayApp, PayAppBase, EmbeddedApp
  12. logger = logging.getLogger(__name__)
  13. class PayAppType(IterConstant):
  14. # 资金池模式只使用ALIPAY,WECHAT,JD_AGGR三种支付方式
  15. ALIPAY = 'alipay'
  16. ALIPAY_FUND_BOOK = 'alipay_fund_book'
  17. WECHAT = 'wechat'
  18. # 各经销商可使用的支付方式(包括JD_AGGR以及ALIPAY+WECHAT)
  19. PLATFORM_PROMOTION = "platform_promotion"
  20. PLATFORM_WALLET = 'platform_wallet'
  21. PLATFORM_RECONCILE ='platform_reconcile'
  22. JD_OPEN = 'jdopen'
  23. MANUAL = 'manual'
  24. SWAP = 'swap'
  25. LEDGER_CONSUME = "ledgerConsume"
  26. PAY_APP_TYPE_TRANSLATION = {
  27. AppPlatformType.ALIPAY: u'支付宝',
  28. AppPlatformType.WECHAT: u'微信',
  29. }
  30. PAY_APP_MAP = {
  31. PayAppType.ALIPAY: 'apps.web.core.models.AliApp',
  32. PayAppType.WECHAT: 'apps.web.core.models.WechatPayApp',
  33. PayAppType.PLATFORM_PROMOTION: 'apps.web.core.models.PlatformPromotionApp',
  34. PayAppType.PLATFORM_WALLET: 'app.web.core.models.PlatformWalletApp',
  35. PayAppType.PLATFORM_RECONCILE: 'app.web.core.models.PlatformReconcileApp',
  36. PayAppType.MANUAL: 'apps.web.core.models.ManualPayApp',
  37. PayAppType.ALIPAY_FUND_BOOK: 'apps.web.core.models.AliFundAccountBookApp'
  38. }
  39. APP_KEY_DELIMITER = '-'
  40. wechat_bound_openid_key = lambda appid: APP_KEY_DELIMITER.join([AppPlatformType.WECHAT, appid])
  41. class BaseAppProxy(object):
  42. def __init__(self, app):
  43. # type: (Optional[EmbeddedApp, WechatPayApp])->None
  44. self._app = app # type: Optional[EmbeddedApp, WechatPayApp]
  45. @property
  46. def app(self):
  47. return self._app
  48. @property
  49. def client(self):
  50. if hasattr(self, '__client__'):
  51. return getattr(self, '__client__')
  52. else:
  53. raise AttributeError('no __client__ attribute')
  54. @property
  55. def occupantId(self):
  56. return self._app.occupantId
  57. @property
  58. def occupant(self):
  59. return self._app.occupant
  60. @property
  61. def bound_openid_key(self):
  62. if not hasattr(self, '__bound_openid_key__'):
  63. raise AttributeError('no __bound_openid_key__ attribute')
  64. return getattr(self, '__bound_openid_key__')
  65. @property
  66. def gateway_type(self):
  67. if not hasattr(self, '__gateway_type__'):
  68. raise AttributeError('no __gateway_type__ attribute')
  69. return getattr(self, '__gateway_type__')
  70. @property
  71. def debug(self):
  72. return self._app.debug
  73. @property
  74. def enable(self):
  75. return self._app.enable
  76. @property
  77. def valid(self):
  78. return self._app.valid
  79. class _BaseMixin(object):
  80. @property
  81. def __app_for_inner__(self):
  82. # type: ()->Union[cast(PayAppBase), EmbeddedApp]
  83. if not hasattr(self, 'app'):
  84. raise AttributeError('no app attribute')
  85. return getattr(self, 'app')
  86. @property
  87. def __client_for_inner__(self):
  88. if not hasattr(self, 'client'):
  89. raise AttributeError('no client attribute')
  90. return getattr(self, 'client')
  91. @property
  92. def __bound_openid_key__(self):
  93. raise AttributeError('no __bound_openid_key__ attribute')
  94. class WechatMixin(_BaseMixin):
  95. @property
  96. def appid(self):
  97. return self.__app_for_inner__.appid
  98. @property
  99. def secret(self):
  100. return self.__app_for_inner__.secret
  101. @classmethod
  102. def reply(cls, msg, ok):
  103. # type: (basestring, bool)->str
  104. response = {
  105. "return_code": "SUCCESS" if ok else "FAIL",
  106. "return_msg": msg
  107. }
  108. return cls.serialize_wechat_xml(response)
  109. def check(self, data, order = True, token = True):
  110. return self.__client_for_inner__.check_signature(data)
  111. @classmethod
  112. def serialize_wechat_xml(cls, payload):
  113. # type:(dict)->str
  114. return dicttoxml.dicttoxml(payload, attr_type = False, custom_root = 'xml', cdata = True)
  115. @property
  116. def __bound_openid_key__(self):
  117. return wechat_bound_openid_key(self.appid)
  118. # @property
  119. # def __gateway_type__(self):
  120. # return AppPlatformType.WECHAT
  121. class AlipayMixin(_BaseMixin):
  122. """
  123. Alipay 支付网关,扩展原库没有的接口 ``alipay.trade.create``
  124. """
  125. @property
  126. def appid(self):
  127. return self.__app_for_inner__.appid
  128. @property
  129. def app_private_key_string(self):
  130. return self.__app_for_inner__.app_private_key_string
  131. @property
  132. def public_key_string(self):
  133. return self.__app_for_inner__.public_key_string
  134. @property
  135. def public_key_cert_string(self):
  136. return self.__app_for_inner__.public_key_cert_string
  137. @property
  138. def root_cert_string(self):
  139. return self.__app_for_inner__.root_cert_string
  140. @property
  141. def app_public_key_cert_string(self):
  142. return self.__app_for_inner__.app_public_key_cert_string
  143. @property
  144. def aes_encrypt_key(self):
  145. return self.__app_for_inner__.aes_encrypt_key
  146. @property
  147. def signKeyType(self):
  148. return self.__app_for_inner__.signKeyType
  149. @property
  150. def __bound_openid_key__(self):
  151. # 支付宝用户ID是唯一的,直接以平台类型区分
  152. return AppPlatformType.ALIPAY
  153. @property
  154. def __client__(self):
  155. return self.__app_for_inner__.client
  156. def check(self, data, pop_sign_type = True):
  157. # type:(dict, bool)->bool
  158. sign = data.pop('sign')
  159. if not sign:
  160. logger.error('has no sign')
  161. return False
  162. return self.__client__.verify(data, sign, pop_sign_type)
  163. class ROLEMetaClass(type):
  164. def __setattr__(self, name, value):
  165. raise NotImplementedError()
  166. def __getattr__(self, item):
  167. if item in self.choices():
  168. return item
  169. else:
  170. raise KeyError()
  171. class ROLE(six.with_metaclass(ROLEMetaClass)):
  172. __role_map = {
  173. 'myuser': {
  174. 'module': 'apps.web.user.models.MyUser',
  175. 'sub_type': 'U'
  176. },
  177. 'dealer': {
  178. 'module': 'apps.web.dealer.models.Dealer',
  179. 'sub_type': 'D'
  180. },
  181. 'subaccount': {
  182. 'module': 'apps.web.dealer.models.SubAccount',
  183. 'sub_type': 'B'
  184. },
  185. 'agent': {
  186. 'module': 'apps.web.agent.models.Agent',
  187. 'sub_type': 'A'
  188. },
  189. 'manager': {
  190. 'module': 'apps.web.management.models.Manager',
  191. 'sub_type': 'M'
  192. },
  193. 'supermanager': {
  194. 'module': 'apps.web.superamdin.models.SuperManager',
  195. 'sub_type': 'S'
  196. },
  197. 'advertiser': {
  198. 'module': 'apps.web.ad.models.Advertiser',
  199. 'sub_type': 'V'
  200. },
  201. 'tester': {
  202. 'module': 'apps.web.test.models.Tester',
  203. 'sub_type': 'T'
  204. },
  205. 'advertisement': {
  206. 'module': 'apps.web.ad.models.Advertisement',
  207. 'sub_type': 'T'
  208. },
  209. 'anonymoususer': {
  210. 'module': 'django.contrib.auth.models.AnonymousUser',
  211. 'sub_type': 'N'
  212. },
  213. 'manufacturer': {
  214. 'module': 'apps.web.management.models.Manager',
  215. 'sub_type': 'M'
  216. }
  217. }
  218. def __init__(self):
  219. raise NotImplementedError()
  220. @classmethod
  221. def choices(cls):
  222. return cls.__role_map.keys()
  223. @classmethod
  224. def from_role_id(cls, role, id):
  225. if role == cls.anonymoususer:
  226. return import_string(cls.__role_map[role]['module'])()
  227. else:
  228. return import_string(cls.__role_map[role]['module']).objects(id = id).get()
  229. @classmethod
  230. def sub_type(cls, role):
  231. return cls.__role_map[role]['sub_type']
  232. @classmethod
  233. def sub_type_list(cls):
  234. return [item['sub_type'] for item in cls.__role_map.values()]