123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import logging
- import dicttoxml
- import six
- from django.utils.module_loading import import_string
- from typing import TYPE_CHECKING, Optional, cast, Union
- from apilib.systypes import IterConstant
- from apps.web.constant import AppPlatformType
- from library.ys.base import PayOpt
- if TYPE_CHECKING:
- from apps.web.core.models import WechatPayApp, PayAppBase, EmbeddedApp, WechatMiniApp
- logger = logging.getLogger(__name__)
- class PayAppType(IterConstant):
- # 资金池模式只使用ALIPAY,WECHAT,JD_AGGR三种支付方式
- ALIPAY = 'alipay'
- WECHAT = 'wechat'
- JD_AGGR = 'jdaggre'
- # 蓝牙特殊处理, 使用小程序绑定的支付方式, 后续可以迁移到京东聚合支付
- WECHAT_MINI = 'wechat_mini'
- # 各经销商可使用的支付方式(包括JD_AGGR以及ALIPAY+WECHAT)
- SAOBEI = 'saobei'
- JD = 'jd'
- DLB = 'dlb'
- YS = 'ys'
- JOS = "jos"
- RCU = "rcu"
- PLATFORM_PROMOTION = "platform_promotion"
- PLATFORM_WALLET = 'platform_wallet'
- PLATFORM_RECONCILE ='platform_reconcile'
- JD_OPEN = 'jdopen'
- MANUAL = 'manual'
- SWAP = 'swap'
- LEDGER_CONSUME = "ledgerConsume"
- PAY_APP_TYPE_TRANSLATION = {
- AppPlatformType.ALIPAY: u'支付宝',
- AppPlatformType.WECHAT: u'微信',
- PayAppType.WECHAT_MINI: u'微信小程序',
- PayAppType.SAOBEI: u'扫呗聚合支付',
- PayAppType.JD_AGGR: u'京东聚合支付',
- PayAppType.DLB: u'哆啦宝聚合支付',
- PayAppType.YS: u'易生聚合支付',
- PayAppType.RCU: u'河南农村信用社',
- PayAppType.JD_OPEN: u'京东聚合支付'
- }
- PAY_APP_MAP = {
- PayAppType.ALIPAY: 'apps.web.core.models.AliApp',
- PayAppType.WECHAT: 'apps.web.core.models.WechatPayApp',
- PayAppType.WECHAT_MINI: 'apps.web.core.models.WechatMiniApp',
- PayAppType.SAOBEI: 'apps.web.core.models.SaobeiPayApp',
- PayAppType.JD_AGGR: 'apps.web.core.models.JDAggrePayApp',
- PayAppType.DLB: 'apps.web.core.models.DlbPayApp',
- PayAppType.YS: 'apps.web.core.models.YsPayApp',
- PayAppType.RCU: 'apps.web.core.models.RuralCreditUnionApp',
- PayAppType.PLATFORM_PROMOTION: 'apps.web.core.models.PlatformPromotionApp',
- PayAppType.PLATFORM_WALLET: 'app.web.core.models.PlatformWalletApp',
- PayAppType.PLATFORM_RECONCILE: 'app.web.core.models.PlatformReconcileApp',
- PayAppType.JD_OPEN: 'apps.web.core.models.JDOpenPayApp',
- PayAppType.MANUAL: 'apps.web.core.models.ManualPayApp'
- }
- APP_KEY_DELIMITER = '-'
- def wechat_bound_openid_key(appid):
- return APP_KEY_DELIMITER.join([AppPlatformType.WECHAT, appid])
- class BaseAppProxy(object):
- def __init__(self, app):
- # type: (Optional[EmbeddedApp, WechatPayApp])->None
- self._app = app # type: Optional[EmbeddedApp, WechatPayApp]
- @property
- def app(self):
- return self._app
- @property
- def client(self):
- if hasattr(self, '__client__'):
- return getattr(self, '__client__')
- else:
- raise AttributeError('no __client__ attribute')
- @property
- def occupantId(self):
- return self._app.occupantId
- @property
- def occupant(self):
- return self._app.occupant
- @property
- def bound_openid_key(self):
- if not hasattr(self, '__bound_openid_key__'):
- raise AttributeError('no __bound_openid_key__ attribute')
- return getattr(self, '__bound_openid_key__')
- @property
- def gateway_type(self):
- if not hasattr(self, '__gateway_type__'):
- raise AttributeError('no __gateway_type__ attribute')
- return getattr(self, '__gateway_type__')
- @property
- def debug(self):
- return self._app.debug
- @property
- def enable(self):
- return self._app.enable
- @property
- def valid(self):
- return self._app.valid
- class _BaseMixin(object):
- @property
- def __app_for_inner__(self):
- # type: ()->Union[cast(PayAppBase), EmbeddedApp]
- if not hasattr(self, 'app'):
- raise AttributeError('no app attribute')
- return getattr(self, 'app')
- @property
- def __client_for_inner__(self):
- if not hasattr(self, 'client'):
- raise AttributeError('no client attribute')
- return getattr(self, 'client')
- @property
- def __bound_openid_key__(self):
- raise AttributeError('no __bound_openid_key__ attribute')
- class WechatMixin(_BaseMixin):
- @property
- def appid(self):
- return self.__app_for_inner__.appid
- @property
- def secret(self):
- return self.__app_for_inner__.secret
- @classmethod
- def reply(cls, msg, ok):
- # type: (basestring, bool)->str
- response = {
- "return_code": "SUCCESS" if ok else "FAIL",
- "return_msg": msg
- }
- return cls.serialize_wechat_xml(response)
- def check(self, data, order = True, token = True):
- return self.__client_for_inner__.check_signature(data)
- @classmethod
- def serialize_wechat_xml(cls, payload):
- # type:(dict)->str
- return dicttoxml.dicttoxml(payload, attr_type = False, custom_root = 'xml', cdata = True)
- @property
- def __bound_openid_key__(self):
- return wechat_bound_openid_key(self.appid)
- # @property
- # def __gateway_type__(self):
- # return AppPlatformType.WECHAT
- class DlbMixin(_BaseMixin):
- @property
- def merchant_no(self):
- return self.__app_for_inner__.merchant_no
- @property
- def shop_no(self):
- return self.__app_for_inner__.shop_no
- @property
- def machine_no(self):
- return self.__app_for_inner__.machine_no
- @property
- def access_key(self):
- return self.__app_for_inner__.access_key
- @property
- def secret_key(self):
- return self.__app_for_inner__.secret_key
- @property
- def __bound_openid_key__(self):
- # 哆啦宝不需要获取openid
- raise AttributeError("no __bound_openid_key__ attribute")
- class YsMixin(_BaseMixin):
- GATEWAY_TYPE_TO_OPT = {
- AppPlatformType.WECHAT: PayOpt.wxPreOrder,
- AppPlatformType.ALIPAY: PayOpt.apPreOrder
- }
- @property
- def channel_id(self):
- return self.__app_for_inner__.channel_id
- @property
- def mer_id(self):
- return self.__app_for_inner__.mer_id
- @property
- def term_id(self):
- return self.__app_for_inner__.term_id
- @property
- def work_key(self):
- return self.__app_for_inner__.work_key
- @property
- def __bound_openid_key__(self):
- # 接口调用的时候获取openid
- raise AttributeError("no __bound_openid_key__ attribute")
- class AlipayMixin(_BaseMixin):
- """
- Alipay 支付网关,扩展原库没有的接口 ``alipay.trade.create``
- """
- @property
- def appid(self):
- return self.__app_for_inner__.appid
- @property
- def app_private_key_string(self):
- return self.__app_for_inner__.app_private_key_string
- @property
- def public_key_string(self):
- return self.__app_for_inner__.public_key_string
- @property
- def public_key_cert_string(self):
- return self.__app_for_inner__.public_key_cert_string
- @property
- def root_cert_string(self):
- return self.__app_for_inner__.root_cert_string
- @property
- def app_public_key_cert_string(self):
- return self.__app_for_inner__.app_public_key_cert_string
- @property
- def aes_encrypt_key(self):
- return self.__app_for_inner__.aes_encrypt_key
- @property
- def signKeyType(self):
- return self.__app_for_inner__.signKeyType
- @property
- def __gateway_type__(self):
- return AppPlatformType.ALIPAY
- @property
- def __bound_openid_key__(self):
- # 支付宝用户ID是唯一的,直接以平台类型区分
- return AppPlatformType.ALIPAY
- @property
- def __client__(self):
- return self.__app_for_inner__.client
- def check(self, data, pop_sign_type = True):
- # type:(dict, bool)->bool
- sign = data.pop('sign')
- if not sign:
- logger.error('has no sign')
- return False
- return self.__client__.verify(data, sign, pop_sign_type)
- class ROLEMetaClass(type):
- def __setattr__(self, name, value):
- raise NotImplementedError()
- def __getattr__(self, item):
- if item in self.choices():
- return item
- else:
- raise KeyError()
- class ROLE(six.with_metaclass(ROLEMetaClass)):
- __role_map = {
- 'myuser': {
- 'module': 'apps.web.user.models.MyUser',
- 'sub_type': 'U'
- },
- 'dealer': {
- 'module': 'apps.web.dealer.models.Dealer',
- 'sub_type': 'D'
- },
- 'subaccount': {
- 'module': 'apps.web.dealer.models.SubAccount',
- 'sub_type': 'B'
- },
- 'agent': {
- 'module': 'apps.web.agent.models.Agent',
- 'sub_type': 'A'
- },
- 'manager': {
- 'module': 'apps.web.management.models.Manager',
- 'sub_type': 'M'
- },
- 'supermanager': {
- 'module': 'apps.web.superamdin.models.SuperManager',
- 'sub_type': 'S'
- },
- 'advertiser': {
- 'module': 'apps.web.ad.models.Advertiser',
- 'sub_type': 'V'
- },
- 'tester': {
- 'module': 'apps.web.test.models.Tester',
- 'sub_type': 'T'
- },
- 'advertisement': {
- 'module': 'apps.web.ad.models.Advertisement',
- 'sub_type': 'T'
- },
- 'anonymoususer': {
- 'module': 'django.contrib.auth.models.AnonymousUser',
- 'sub_type': 'N'
- },
- 'manufacturer': {
- 'module': 'apps.web.management.models.Manager',
- 'sub_type': 'M'
- }
- }
- def __init__(self):
- raise NotImplementedError()
- @classmethod
- def choices(cls):
- return cls.__role_map.keys()
- @classmethod
- def from_role_id(cls, role, id):
- if role == cls.anonymoususer:
- return import_string(cls.__role_map[role]['module'])()
- else:
- return import_string(cls.__role_map[role]['module']).objects(id = id).get()
- @classmethod
- def sub_type(cls, role):
- return cls.__role_map[role]['sub_type']
- @classmethod
- def sub_type_list(cls):
- return [item['sub_type'] for item in cls.__role_map.values()]
|