# -*- 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' % ( 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' # 虚拟卡消费