123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import random
- import uuid
- from django.utils.module_loading import import_string
- from typing import TYPE_CHECKING, Optional, cast
- from apilib.systypes import IterConstant
- from apps.web.core import PAY_APP_MAP, APP_KEY_DELIMITER, PayAppType, BaseAppProxy
- if TYPE_CHECKING:
- from apps.web.core.models import PayAppBase
- from apps.web.core.payment.type_checking import PaymentGatewayT
- from apps.web.common.transaction.pay import RechargeRecordT
- class _PaymentGateway(BaseAppProxy):
- def __init__(self, app):
- super(_PaymentGateway, self).__init__(app)
- @property
- def pay_app_type(self):
- if hasattr(self.app, 'pay_app_type'):
- return getattr(self.app, 'pay_app_type')
- else:
- raise AttributeError('no __pay_app_type__ attribute')
- @property
- def gateway_type(self):
- if hasattr(self, '__gateway_type__'):
- return getattr(self, '__gateway_type__')
- else:
- raise AttributeError('no __gateway_type__ attribute')
- @property
- def gateway_key(self):
- if hasattr(self.app, '__gateway_key__'):
- key = getattr(self.app, '__gateway_key__')
- return APP_KEY_DELIMITER.join([self.app.pay_app_type, key])
- else:
- raise AttributeError('no __gateway_key__ attribute')
- @classmethod
- def parse_gateway_key(cls, gateway_key, default_pay_app_type = PayAppType.WECHAT):
- # type: (str, str)->tuple
- tokens = gateway_key.split(APP_KEY_DELIMITER)
- if tokens[0] in PayAppType.choices():
- return tokens[0], tokens[1], tokens[2:]
- else:
- return default_pay_app_type, tokens[0], tokens[1:]
- @classmethod
- def get_app_from_gateway_key(cls, gateway_key, default_pay_app_type = PayAppType.WECHAT):
- pay_app_type, occupant_id, tokens = cls.parse_gateway_key(gateway_key, default_pay_app_type)
- pay_app_name = PAY_APP_MAP[pay_app_type]
- app_cls = import_string(pay_app_name)
- factory_fun = getattr(app_cls, '__from_gateway_key__')
- app = factory_fun(occupant_id, tokens) # type: Optional[cast(PayAppBase)]
- return app
- class PaymentGateway(_PaymentGateway):
- """
- 支付网关基类
- """
- GATEWAY_PREFIX = 'gk{}'.format(APP_KEY_DELIMITER)
- class TradeStatus(IterConstant):
- Init = 'init'
- Unknown = 'unknown'
- Success = 'success'
- Paying = 'paying'
- Closed = 'closed'
- Finished = 'finished'
- Cancel = 'cancel'
- Refund = 'fefund'
- Refunding = 'refunding'
- RefundFail = 'refundFail'
- Error = 'error'
- @classmethod
- def from_gateway_key(cls, gateway_type, gateway_key, default_pay_app_type):
- pay_app = cls.get_app_from_gateway_key(gateway_key = gateway_key,
- default_pay_app_type = default_pay_app_type)
- return pay_app.new_gateway(gateway_type)
- @classmethod
- def clone_from_order(cls, order): # type:(RechargeRecordT) -> PaymentGatewayT
- gateway_type = order.my_gateway
- gateway_key = order.pay_gateway_key
- pay_app_type = order.pay_app_type
- pay_app = cls.get_app_from_gateway_key(
- gateway_key = gateway_key,
- default_pay_app_type = pay_app_type
- )
- if not pay_app.occupant:
- source_cls = import_string('apps.web.{}.models.{}'.format(pay_app.role, pay_app.role.capitalize()))
- pay_app.occupant = source_cls.objects.get(id = pay_app.occupantId)
- return pay_app.new_gateway(gateway_type)
- def api_trade_query(self, out_trade_no = None, trade_no = None):
- raise NotImplementedError('sub class must implement api_trade_query')
- def refund_to_user(self, out_trade_no, out_refund_no, refund_fee, total_fee, refund_reason, **kwargs):
- raise NotImplementedError('sub class must implement refund_to_user')
- # service 2位 18, 28 ,38
- # product 4位 0001, 0002, 0003
- # WF180001201712281209393393822345
- @staticmethod
- def generate_order_no(service, product):
- return '%s%s%s%s%s' % (
- service, product, datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
- (str(abs(hash(uuid.uuid1())))[0:6]).rjust(6, '0'),
- random.randint(1000, 9999))
- def withdraw_source_key(self):
- return self.occupant.withdraw_source_key(self.app)
- def api_refund_query(self, out_refund_no, out_trade_no = None):
- raise NotImplementedError('must implement api_refund_query.')
- class WithdrawGateway(_PaymentGateway):
- """
- 提现网关基类
- """
- LEDGER_PREFIX = 'ledger'
- NO_LEDGER_PREFIX = 'noledger'
- def __init__(self, app):
- # type: (cast(PayAppBase))->None
- super(WithdrawGateway, self).__init__(app)
- @classmethod
- def is_ledger(cls, source_key):
- # type: (str)->bool
- return source_key.startswith(cls.LEDGER_PREFIX)
- @property
- def support_withdraw(self):
- return self.app.supportWithdraw
- @property
- def support_withdraw_bank(self):
- return self.app.supportWithdrawBank
- @classmethod
- def from_withdraw_gateway_key(cls, withdraw_gateway_key, gateway_version):
- pay_app = cls.get_app_from_gateway_key(gateway_key = withdraw_gateway_key,
- default_pay_app_type = PayAppType.WECHAT) # type: cast(PayAppBase)
- return pay_app.new_withdraw_gateway(gateway_version = gateway_version)
- @property
- def manual_withdraw(self):
- # type:()->bool
- return self.app.manual_withdraw
- def get_transfer_result_via_bank(self, order_no):
- """
- 查询银行卡提现的返回结果
- :return:
- """
- raise NotImplementedError()
- def get_transfer_result_via_changes(self, order_no):
- """
- 查询现金提现的返回结果
- :return:
- """
- raise NotImplementedError()
- def withdraw_via_bank(self, order_no, total_amount, bank_card, order_title = u'服务款项'):
- """
- 提现到银行卡
- :return:
- """
- raise NotImplementedError()
- def withdraw_via_changes(self, amount, payOpenId, order_no, real_user_name, subject):
- """
- 提现到现金
- :return:
- """
- raise NotImplementedError()
|