123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import logging
- from django.conf import settings
- from typing import TYPE_CHECKING
- from apilib.monetary import RMB
- from apilib.utils_sys import memcache_lock
- from apps.web.core import PayAppType
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.payment import PaymentGateway
- from apps.web.dealer.define import REFUND_NOTIFY_URL
- from apps.web.dealer.models import RefundDealerRechargeRecord, DealerRechargeRecord
- from apps.web.exceptions import UserServerException
- from library.wechatbase.exceptions import WeChatPayException
- logger = logging.getLogger(__name__)
- if TYPE_CHECKING:
- pass
- def refund_cash_to_dealer(dealer_recharge_record, refundFee):
- if dealer_recharge_record.product == DealerRechargeRecord.ProductType.SimCard:
- return RefundSimRecharge(dealer_recharge_record, refundFee).execute()
- else:
- raise UserServerException(u'目前不支持该种类型订单退款')
- class RefundCash(object):
- # 最长的查询分账时间
- MAX_LEDGER_CHECK_TIME = 15
- def __init__(self, rechargeOrder, refundFee): # type:(DealerRechargeRecord, RMB) -> None
- self._payOrder = rechargeOrder
- self.refundFee = refundFee
- @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 execute(self):
- """
- 执行退款的动作
- :return:
- """
- lockKey = "refund_dealer_recharge_cash_{}".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 paras, 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)))
- payGateway = PaymentGateway.clone_from_order(self.payOrder) # type: PaymentGateway
- refundOrder.processing()
- try:
- if payGateway.pay_app_type == PayAppType.WECHAT:
- # 微信的退款方式
- try:
- result = payGateway.refund_to_user(
- out_trade_no = self.outTradeNo,
- out_refund_no = refundOrder.orderNo,
- refund_fee = self.refundFee,
- total_fee = self.totalFee,
- refund_reason = u'退费',
- notify_url = REFUND_NOTIFY_URL.WECHAT_REFUND_BACK)
- except WeChatPayException as e:
- logger.info('refund failed , refund orderNo = {} reason = {}'.format(refundOrder.orderNo, e))
- refundOrder.fail(errorCode = e.errCode, errorDesc = e.errMsg)
- raise UserServerException('{}({})'.format(e.errMsg, e.errCode))
- logger.info('WECHAT Refund request successfully! return = {}'.format(result))
- else:
- refundOrder.fail(errorDesc = u"不支持的退款模式")
- raise UserServerException(u"不支持的退款模式")
- except ServiceException as se:
- raise se
- except Exception as ee:
- # 这一步就不再更改订单的状态 由于不知道是退款前出错还是退款后出错 使用poll拉取订单状态来更新
- logger.exception(ee)
- raise UserServerException(u'未知异常')
- 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'目前仅支持不分账情况下退账。')
|