123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import string
- from mongoengine import NotUniqueError
- from typing import TYPE_CHECKING
- from apilib.systypes import IntEnum, IterConstant, StrEnum
- from apilib.utils_string import get_random_str
- from apps.web.core.exceptions import WithdrawError
- if TYPE_CHECKING:
- from apps.web.common.models import CapitalUser, WithdrawRecord
- class WithdrawStatus(IntEnum):
- SUBMITTED = 0
- SUCCEEDED = 1
- PROCESSING = 2
- FAILED = 3
- CLOSED = 4
- REFUND = 5
- BANK_PROCESSION = 6
- @classmethod
- def finished_status(cls):
- return [cls.SUCCEEDED, cls.CLOSED, cls.REFUND]
- class WITHDRAW_PAY_TYPE(IterConstant):
- BANK = 'bank'
- WECHAT = 'wechat'
- ALIPAY = 'alipay'
- WITHDRAW_STATE_TRANSLATION = {
- WithdrawStatus.SUBMITTED: u'已提交申请',
- WithdrawStatus.SUCCEEDED: u'提现成功',
- WithdrawStatus.PROCESSING: u'提现申请已经受理',
- WithdrawStatus.FAILED: u'提现失败',
- WithdrawStatus.CLOSED: u'关闭',
- WithdrawStatus.REFUND: u'银行退单',
- WithdrawStatus.BANK_PROCESSION: u'银行正在处理中'
- }
- class WithdrawResult(object):
- def __init__(self, result, err_code, refund, message, show_message, callResult = None):
- self.result = result
- self.err_code = err_code
- self.refund = refund
- self.message = message
- self.show_message = show_message
- self.callResult = callResult
- def __repr__(self):
- return 'WithdrawResult<errCode=%s, message=%s, callResult=%s>' % (
- self.err_code, self.message, str(self.callResult))
- class WithdrawHandler(object):
- def __init__(self, payee, record):
- # type: (CapitalUser, WithdrawRecord) -> None
- self.payee = payee
- self.record = record
- def on_revoke(self):
- pass
- def revoke(self, remarks, description):
- # type:(basestring, basestring)->None
- """
- 提现失败返回金额到提现账户。在以下场景调用:
- 1、提现账户提现报错,并且明确一定是失败的情况下自动调用;
- 2、资金平台确认订单失败,调用该接口退款
- """
- from apps.web.common.models import WithdrawRefundRecord
- from apps.web.common.errors import DuplicatedRefundRecordFound
- try:
- WithdrawRefundRecord(withdraw_record_id = self.record.id).save()
- except NotUniqueError:
- raise DuplicatedRefundRecordFound('record = %r' % (self.record,))
- success = self.record.revoke(remarks, description)
- if success:
- self.payee.recover_frozen_balance(
- self.record.incomeType,
- self.record.amount,
- self.record.source_key,
- self.record.order,
- )
- self.on_revoke()
- else:
- raise WithdrawError(u'更新提现状态失败(1001)')
- def on_approve(self):
- pass
- def approve(self, **kwargs):
- if 'remarks' not in kwargs:
- kwargs['remarks'] = u'提现成功'
- if 'description' not in kwargs:
- kwargs['description'] = u'提现成功'
- success = self.record.succeed(**kwargs)
- if success:
- self.payee.clear_frozen_balance(
- self.record.incomeType
- )
- self.on_approve()
- else:
- raise WithdrawError(u'更新提现状态失败(1002)')
- def on_fail(self):
- pass
- def fail(self, remarks, description):
- success = self.record.fail(remarks, description)
- if success:
- self.on_fail()
- else:
- raise WithdrawError(u'更新提现状态失败(1003)')
- def on_processing(self):
- pass
- def processing(self, remarks, description):
- success = self.record.set_processing(remarks = remarks, description = description)
- if success:
- self.on_processing()
- else:
- raise WithdrawError(u'更新提现状态失败(1005)')
- def on_bank_processing(self):
- pass
- def bank_processing(self, **kwargs):
- success = self.record.set_bank_processing(**kwargs)
- if success:
- self.on_bank_processing()
- else:
- raise WithdrawError(u'更新提现状态失败(1006)')
- def translate_withdraw_state(state):
- return WITHDRAW_STATE_TRANSLATION.get(state)
- class OrderNoMaker(object):
- @classmethod
- def _order_prefix(cls, main_type, sub_type):
- return '{}{}'.format(main_type, sub_type)
- @classmethod
- def make_order_no_32(cls, identifier, main_type, sub_type):
- # type: (str, str, str)->str
- # time:14,prefix:2,identifier:13,resered:3
- return '{time}{prefix}{identifier}{reserved}'.format(
- time = datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
- prefix = cls._order_prefix(main_type, sub_type),
- identifier = '{:0>13}'.format(identifier[-13:]).upper(),
- reserved = get_random_str(3, string.digits + string.uppercase))
- class OrderMainType(StrEnum):
- PAY = 'P' # 支付订单
- CONSUME = 'C' # 消费订单
- REFUND = 'R' # 退款单
- WITHDRAW = 'W' # 提现单
- '''
- UserPaySubType - 用户支付订单子类型
- DealerPaySubType - 经销商支付订单子类型
- 子类型在UserPaySubType和DealerPaySubType中是唯一的, 不能重复
- '''
- class RefundSubType(IterConstant):
- REFUND = 'R'
- class UserPaySubType(IterConstant):
- QUICK_PAY = 'Q'
- RECHARGE = 'R'
- CARD_RECHARGE = 'C'
- TERMINAL_RECHARGE = 'T' # 中创将模块作为终端充值机使用(实际是设备充值)
- VIRTUAL_CARD_RECHARGE_RECORD = 'V'
- CASH_PAY = 'P' # 后付费订单直接支付
- MONTHLY_PACKAGE = "M"
- INSURANCE = "I"
- REDPACK = 'F'
- MIX = "X"
- CARD_RECHARGE_RECORD = 'D' # 這個不是真正的訂單類型
- SWAP = 'W'
- class DealerPaySubType(IterConstant):
- SIM_CARD = 'S'
- AUTO_SIM_CARD = 'U'
- MANUAL_SIM_CARD = 'M'
- JOIN = 'J'
- API_COST = 'A'
- DISABLE_AD = 'D'
- SIM_ORDER_VERIFY = 'V'
- class UserConsumeSubType(StrEnum):
- """
- 消费订单子类型
- """
- NETPAY = 'N' # 自助设备消费
- CARD = 'C'
- COIN = 'I'
- VIRTUAL_CARD = 'V' # 虚拟卡消费
|