123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import logging
- from django.conf import settings
- from typing import TYPE_CHECKING
- from apilib.monetary import RMB, Percent
- from apilib.utils_sys import memcache_lock
- from apps.web.common.transaction.refund import RefundCashMixin
- from apps.web.dealer.define import DealerConst
- from apps.web.dealer.models import RefundDealerRechargeRecord, DealerRechargeRecord, Dealer
- from apps.web.dealer.proxy import record_income_proxy
- from apps.web.exceptions import UserServerException
- from apps.web.user.models import RechargeRecord
- logger = logging.getLogger(__name__)
- if TYPE_CHECKING:
- pass
- def refund_post_pay(refundOrder, success):
- pass
- def refund_cash_to_dealer(dealer_recharge_record, refundFee, isInsure = False):
- if dealer_recharge_record.product == DealerRechargeRecord.ProductType.SimCard:
- return RefundSimRecharge(dealer_recharge_record, refundFee, u'流量卡退款').execute(
- frozen_callable = None, refund_callable = refund_post_pay)
- elif dealer_recharge_record.product == DealerRechargeRecord.ProductType.AutoSimCard:
- # return RefundSimWallet(dealer_recharge_record, refundFee).execute()
- # else:
- raise UserServerException(u'目前不支持该种类型订单退款')
- else:
- raise UserServerException(u'目前不支持该种类型订单退款')
- class RefundCash(RefundCashMixin):
- MAX_LEDGER_CHECK_TIME = 15 # 最长的查询分账时间
- def __init__(self, rechargeOrder, refundFee, reason): # type:(DealerRechargeRecord, RMB, basestring) -> None
- super(RefundCash, self).__init__(rechargeOrder, refundFee)
- self.reason = reason
- def pre_check(self):
- """
- 退款的预检查
- :return:
- """
- # 首先检查退款的金额 原则上退款金额不能小于0 不能大于交易定安的金额
- if self.refundFee <= RMB(0) or self.refundFee > self.totalFee:
- raise UserServerException(u"退费金额错误")
- refundOrder = RefundDealerRechargeRecord.objects.filter(
- rechargeObjId = self.paySubOrder.id).first() # type: RefundDealerRechargeRecord
- if refundOrder:
- if refundOrder.is_successful:
- raise UserServerException(u"该单已经退单")
- else:
- raise UserServerException(u"订单正在退款中")
- def execute(self, frozen_callable, refund_callable, notify_url = None):
- """
- 执行退款的动作
- :return:
- """
- lockKey = "refund_dealer_recharge_cash_{}".format(self.paySubOrder.id)
- with memcache_lock(key = lockKey, value = self.paySubOrder.id, expire = 360) as acquired:
- if not acquired:
- raise UserServerException(u"退款订单正在处理,等订单结束后,您才能再次重试哦")
- self.pre_check()
- refundOrder = RefundDealerRechargeRecord.issue(self.payOrder, self.refundFee)
- logger.info('refund paras: {} {}'.format(refundOrder.orderNo, self.refund_paras))
- refundOrder.processing()
- try:
- self.submit_refund(
- refundOrder, None, self.reason, notify_url or refundOrder.notify_url, refund_callable)
- except Exception:
- import traceback
- logger.warning(
- 'Refund request failure! orderNo = {}; e = {}'.format(refundOrder.orderNo, traceback.format_exc()))
- finally:
- pass
- return refundOrder
- class RefundSimRecharge(RefundCash):
- def pre_check(self):
- super(RefundSimRecharge, self).pre_check()
- for partition in self.payOrder.settleInfo['partition']:
- if partition['id'] != settings.MY_PRIMARY_AGENT_ID and partition['earned'] > 0:
- raise UserServerException(u'目前仅支持不分账情况下退账。')
- class RefundInsureRecharge(RefundCash):
- def pre_check(self):
- if self.refundFee <= RMB(0) or self.refundFee > self.totalFee: # DealerChargeRecord中的退费总额是负数
- raise UserServerException(u"退费金额错误")
- # 目前只支持一个单,退一次,不允许退多次
- refundOrder = RefundDealerRechargeRecord.objects.filter(
- rechargeObjId = self.paySubOrder.id).first() # type: RefundDealerRechargeRecord
- if refundOrder:
- if refundOrder.is_successful:
- raise UserServerException(u"该单已经退单")
- else:
- raise UserServerException(u"订单正在退款中")
- class RefundToWallet(object):
- def __init__(self, rechargeOrder, refundFee, reason, subType, via, source):
- self._payOrder = rechargeOrder
- self.refundFee = refundFee
- self.reason = reason
- self.subType = subType
- self.via = via
- self.source = source
- @property
- def outTradeNo(self):
- """
- 交易单号
- :return:
- """
- return self._payOrder.orderNo
- @property
- def totalFee(self):
- return RMB(round(float(self._payOrder.totalFee) / 100, 2))
- @property
- def payOrder(self):
- """
- 交易订单 即支付订单 与第三方系统产生关联的订单
- :return:
- """
- return self._payOrder
- def pre_check(self):
- """
- 退款的预检查
- :return:
- """
- # 首先检查退款的金额 原则上退款金额不能小于0 不能大于交易定安的金额
- if self.refundFee <= RMB(0) or self.refundFee > self.totalFee:
- raise UserServerException(u"退费金额错误")
- # 检查退款订单是否已经存在 是否已经退款成功
- refundOrder = RefundDealerRechargeRecord.objects.filter(
- rechargeObjId = self._payOrder.id).first() # type: RefundDealerRechargeRecord
- if refundOrder:
- if refundOrder.is_successful:
- raise UserServerException(u"该单已经退单")
- else:
- raise UserServerException(u"订单正在退款中")
- def refund_dealer_balance(self, refundFee):
- source_key = self._payOrder.withdraw_source_key
- income_type = DealerConst.MAP_SOURCE_TO_TYPE[self.source]
- dealer = Dealer.objects(id = self._payOrder.dealerId).first()
- if not dealer:
- return False
- fundKey = dealer.fund_key(income_type = income_type, source_key = source_key)
- queryFilter = {
- '_id': dealer.id
- }
- update = {
- '$inc': {'{fundKey}.balance'.format(fundKey = fundKey): (refundFee).mongo_amount}
- }
- result = Dealer.get_collection().update_one(queryFilter, update, upsert = False)
- if result.matched_count == 1 and result.modified_count == 1:
- return True
- else:
- return False
- def execute(self, refund_callable = None):
- """
- 执行退款的动作
- :return:
- """
- lockKey = "refund_dealer_recharge_wallet_{}".format(self._payOrder.id)
- with memcache_lock(key = lockKey, value = self._payOrder.id, expire = 360) as acquired:
- if not acquired:
- raise UserServerException(u"退款订单正在处理,等订单结束后,您才能再次重试哦")
- self.pre_check()
- refundOrder = RefundDealerRechargeRecord.issue(self.payOrder, self.refundFee)
- logger.info(
- 'refund[wallet], order = %s out_refund_no=%s, out_trade_no=%s, refund_fee=%s, total_fee=%s' % (
- self._payOrder.orderNo, self.payOrder.orderNo, refundOrder.orderNo, self.refundFee,
- str(float(self.payOrder.totalFee) / 100)))
- refundOrder.processing()
- try:
- self.refund_dealer_balance(self.refundFee) # 先把钱包的余额返回
- income_record = RechargeRecord.issue_refund_order(self.payOrder, self.refundFee, self.subType,
- self.via) # 补充一条充值记录
- except Exception as e:
- logger.exception(e)
- refundOrder.fail(errorCode = 'EXCEPTION', errorDesc = u'退款过程发生异常')
- raise e
- record_income_proxy(self.source, income_record, {
- "owner": [
- {
- "money": RMB(income_record.money).mongo_amount,
- "role": "owner",
- "share": Percent("100.0").mongo_amount,
- "id": str(income_record.ownerId)
- }
- ],
- 'partner': []
- })
- refundOrder.succeed(finishedTime = datetime.datetime.now())
- if refund_callable: # 用于退款到钱包后的善后工作,比如扣除代理商的分成,补充退款记录
- refund_callable(refundOrder, True)
- return refundOrder
|