transaction_deprecated.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import time
  6. import uuid
  7. from bson import ObjectId
  8. from mongoengine import NotUniqueError
  9. from typing import TYPE_CHECKING, Dict
  10. from apilib.monetary import VirtualCoin, RMB
  11. from apilib.utils import flatten
  12. from apps.web.common.proxy import ClientDealerIncomeModelProxy
  13. from apps.web.common.transaction.refund import RefundCashMixin, RefundManager
  14. from apps.web.constant import USER_RECHARGE_TYPE, PARTITION_ROLE, RechargeRecordVia, AppPlatformType
  15. from apps.web.core import PayAppType, ROLE
  16. from apps.web.core.exceptions import ParameterError
  17. from apps.web.core.payment import WithdrawGateway
  18. from apps.web.dealer.define import DEALER_INCOME_SOURCE, DEALER_INCOME_TYPE
  19. from apps.web.device.models import Group
  20. from apps.web.exceptions import UserServerException
  21. from apps.web.user.models import MyUser, RechargeRecord, RefundMoneyRecord, Card, UserVirtualCard, MonthlyPackage
  22. logger = logging.getLogger(__name__)
  23. if TYPE_CHECKING:
  24. from apps.web.dealer.proxy import DealerIncomeProxy
  25. def refund_money(device, money, openId):
  26. if VirtualCoin(money) <= VirtualCoin(0):
  27. logger.debug('{} is zero. not to refund.'.format(VirtualCoin(money)))
  28. return
  29. groupId = device['groupId']
  30. group = Group.get_group(groupId)
  31. if group.is_free:
  32. logger.info('group(%s) is set to free, refund_money will not proceed' % (device['groupId'],))
  33. return
  34. user = MyUser.objects(openId = openId, groupId = groupId).get() # type: MyUser
  35. user.refund(VirtualCoin(money))
  36. # 添加一条充值记录
  37. orderNo = str(uuid.uuid4())
  38. try:
  39. newRcd = RechargeRecord(orderNo = orderNo,
  40. coins = money, openId = openId, groupId = device['groupId'],
  41. devNo = device['devNo'], logicalCode = device['logicalCode'],
  42. ownerId = device['ownerId'],
  43. groupName = group['groupName'], groupNumber = device['groupNumber'],
  44. address = group['address'], wxOrderNo = u'设备退币',
  45. devTypeName = device.devTypeName, nickname = '',
  46. result = 'success', via = 'refund')
  47. newRcd.save()
  48. except Exception, e:
  49. logger.exception('update record for feedback coins error=%s,orderNo=%s' % (e, orderNo))
  50. def refund_cash(recharge_record, refundFee, **kwargs):
  51. # type:(RechargeRecord, RMB, Dict)->RefundMoneyRecord
  52. """
  53. 新的执行退款 为了保持导包顺序不变
  54. :param recharge_record:
  55. :param refundFee:
  56. :type kwargs: object
  57. :return:
  58. """
  59. if recharge_record.via in [
  60. RechargeRecordVia.Balance,
  61. RechargeRecordVia.Cash,
  62. RechargeRecordVia.Card,
  63. RechargeRecordVia.VirtualCard,
  64. RechargeRecordVia.MonthlyPackage,
  65. ]:
  66. return RefundCash(recharge_record, refundFee, **kwargs).execute(
  67. frozen_callable = frozen_refund_func, refund_callable = refund_post_pay)
  68. else:
  69. raise UserServerException(u'不支持该类型订单退款')
  70. class RefundCash(RefundCashMixin):
  71. MAX_LEDGER_CHECK_TIME = 15 # 最长的查询分账时间
  72. def __init__(self, rechargeOrder, refundFee, **kwargs):
  73. # type:(RechargeRecord, RMB, dict) -> None
  74. super(RefundCash, self).__init__(rechargeOrder, refundFee)
  75. self.extraInfo = kwargs
  76. # self._nextSeq = 1
  77. def check_wallet(self, proxy, order):
  78. partition_map = proxy.partition_map
  79. for partition in list(flatten(partition_map.values())):
  80. if partition['role'] == PARTITION_ROLE.OWNER:
  81. leftBalance = order.owner.sub_balance(
  82. income_type = DEALER_INCOME_TYPE.DEVICE_INCOME,
  83. source_key = order.withdraw_source_key,
  84. only_ledger = True)
  85. if abs(RMB(partition['money'])) > leftBalance:
  86. raise UserServerException(u"您的钱包余额不足,无法退款。")
  87. elif partition['role'] == PARTITION_ROLE.PARTNER:
  88. from apps.web.dealer.models import Dealer
  89. dealer = Dealer.objects(id = partition['id']).first()
  90. leftBalance = dealer.sub_balance(
  91. income_type = DEALER_INCOME_TYPE.DEVICE_INCOME,
  92. source_key = order.withdraw_source_key)
  93. if abs(RMB(partition['money'])) > leftBalance:
  94. raise UserServerException(u"您的分账合伙人钱包余额不足,无法退款(1001)。")
  95. else:
  96. from apps.web.agent.models import Agent
  97. from apps.web.agent.define import AGENT_INCOME_TYPE
  98. agent = Agent.objects(id = partition['id']).first()
  99. leftBalance = agent.sub_balance(
  100. income_type = AGENT_INCOME_TYPE.DEALER_DEVICE_FEE,
  101. source_key = order.withdraw_source_key)
  102. if abs(RMB(partition['money'])) > leftBalance:
  103. raise UserServerException(u"您的分账合伙人钱包余额不足,无法退款(1002)。")
  104. def pre_check(self):
  105. """
  106. 退款的预检查
  107. :return:
  108. """
  109. if self.refundFee <= RMB(0) or self.refundFee > self.subTotalFee:
  110. raise ParameterError(u"退费金额错误")
  111. if 'deductCoins' in self.extraInfo:
  112. deductCoins = self.extraInfo['deductCoins']
  113. if deductCoins < VirtualCoin(
  114. 0) or deductCoins > self.subTotalCoins:
  115. raise ParameterError(u"扣除用户金币数目错误")
  116. check_end_time = int(time.time()) + self.MAX_LEDGER_CHECK_TIME
  117. if not self.paySubOrder.is_success:
  118. raise UserServerException(u'非成功订单无法进行退款')
  119. while not self.paySubOrder.is_ledgered and int(time.time()) < check_end_time:
  120. logger.debug('{} is not allocated. wait to be allocated.'.format(repr(self.paySubOrder)))
  121. time.sleep(5)
  122. self.paySubOrder.reload()
  123. proxy = ClientDealerIncomeModelProxy.get_one(ref_id = self.paySubOrder.id) # type: DealerIncomeProxy
  124. if not proxy:
  125. raise UserServerException(u"订单尚未分账,无法退款(10002)")
  126. if self.paySubOrder.gateway == AppPlatformType.ALIPAY:
  127. over_time = 90 * 24 * 60 * 60
  128. else:
  129. over_time = 365 * 24 * 60 * 60
  130. if (datetime.datetime.now() - self.paySubOrder.finishedTime).total_seconds() >= over_time:
  131. raise UserServerException(u'超期订单不允许退款')
  132. checkWallet = self.extraInfo.get('checkWallet', False)
  133. if checkWallet and WithdrawGateway.is_ledger(source_key = self.paySubOrder.withdraw_source_key):
  134. self.check_wallet(proxy, self.paySubOrder)
  135. return proxy
  136. def create_refund_order(self, **extraInfo):
  137. refundOrder = RefundMoneyRecord.issue(
  138. self.paySubOrder, self.refundFee, **extraInfo)
  139. refundOrder.pay_sub_order = self.paySubOrder
  140. return refundOrder
  141. def execute(self, frozen_callable, refund_callable, notify_url = None):
  142. """
  143. 执行退款的动作
  144. 对于经销商商户的流程: 检查 >> 建单 >> 扣除用户金额 >> 退款 >> 收到退款成功通知后建立负收益单和扣除经销商的记录金额
  145. 对于资金池商的流程: 检查 >> 建单 >> 扣除用户金额 >> 建立负单和扣除经销商的记录金额 >> 退款
  146. :return:
  147. """
  148. proxy = self.pre_check()
  149. try:
  150. refundOrder = self.create_refund_order(**self.extraInfo) # type: RefundMoneyRecord
  151. except NotUniqueError:
  152. raise UserServerException(u'已经有退款订单正在进行')
  153. logger.info('refund paras: {} {}'.format(refundOrder.orderNo, self.refund_paras))
  154. split_map = proxy.partition_map
  155. refund_income_order = self.paySubOrder.issue_refund_income_order(
  156. refundOrder, split_map) # type: RechargeRecord
  157. frozen_callable(refundOrder) # 对资金实体进行退款冻结(用户余额,卡余额等)
  158. try:
  159. self.submit_refund(
  160. refundOrder, refund_income_order.partition_map, u'现金退款',
  161. notify_url or refundOrder.notify_url, refund_callable)
  162. except Exception:
  163. import traceback
  164. logger.warning(
  165. 'Refund request failure! orderNo = {}; e = {}'.format(refundOrder.orderNo, traceback.format_exc()))
  166. finally:
  167. refundOrder.reload()
  168. if refundOrder.is_closed or refundOrder.is_success:
  169. # 终态已经调用了post_pay, 所以不在做任何处理
  170. pass
  171. elif refundOrder.my_payment_gateway.occupant.role == ROLE.agent:
  172. # 资金池情况下认为成功, 冻结运营商金额
  173. refund_income_order.result = RechargeRecord.PayResult.SUCCESS
  174. refund_income_order.finishedTime = datetime.datetime.now()
  175. refund_income_order.save()
  176. from apps.web.report.ledger import Ledger
  177. ledger = Ledger(refund_income_order.via, refund_income_order)
  178. ledger.execute(stats = True)
  179. return refundOrder
  180. class RetryRefundCash(RefundCashMixin):
  181. def __init__(self, refundOrder): # type:(RefundMoneyRecord) -> None
  182. super(RetryRefundCash, self).__init__(refundOrder.pay_sub_order, refundOrder.money)
  183. self.refundOrder = refundOrder
  184. def pre_check(self):
  185. """
  186. 退款的预检查
  187. :return:
  188. """
  189. if self.refundFee <= RMB(0) or self.refundFee > self.subTotalFee:
  190. raise ParameterError(u"退费金额错误")
  191. deductCoins = self.refundOrder.deductCoins
  192. if deductCoins < VirtualCoin(0) or deductCoins > self.subTotalCoins:
  193. raise ParameterError(u"扣除用户金币数目错误")
  194. if not self.refundOrder.is_fail and not self.refundOrder.is_no_order:
  195. raise UserServerException(u'状态非错误的订单不能重试')
  196. proxy = ClientDealerIncomeModelProxy.get_one(ref_id = self.paySubOrder.id)
  197. if not proxy:
  198. raise UserServerException(u"订单尚未分账,无法退款(10002)")
  199. if self.refundOrder.checkWallet and WithdrawGateway.is_ledger(source_key = self.paySubOrder.withdraw_source_key):
  200. self.check_wallet(proxy, self.paySubOrder)
  201. return proxy
  202. def execute(self, frozen_callable, refund_callable, notify_url = None):
  203. """
  204. 执行退款的动作
  205. 对于经销商商户的流程: 检查 >> 建单 >> 扣除用户金额 >> 退款 >> 收到退款成功通知后建立负收益单和扣除经销商的记录金额
  206. 对于资金池商的流程: 检查 >> 建单 >> 扣除用户金额 >> 建立负单和扣除经销商的记录金额 >> 退款
  207. :return:
  208. """
  209. proxy = self.pre_check()
  210. logger.info('retry refund paras: {} {}'.format(self.refundOrder.orderNo, self.refund_paras))
  211. puller = RefundManager().get_poller(self.refundOrder.pay_app_type)
  212. done = puller(self.refundOrder).pull(refund_post_pay)
  213. if done:
  214. return
  215. self.refundOrder.reload()
  216. if not self.refundOrder.is_fail and not self.refundOrder.is_no_order:
  217. logger.debug('refund order {} is not in fail status.'.format(str(self.refundOrder)))
  218. return
  219. if self.refundOrder.retryCount > 10:
  220. matched = self.refundOrder.closed(errorCode = 'TIMEOUT', errorDesc = u'重试次数超限,退款失败')
  221. if matched:
  222. return refund_post_pay(self.refundOrder, False)
  223. refund_income_order = self.refundOrder.refund_income_order
  224. if not refund_income_order:
  225. if 'billSplitOfOwner' in self.paySubOrder.attachParas: # 老的商户分账模式
  226. if "billSplitList" in self.paySubOrder.attachParas:
  227. owner_split = self.paySubOrder.attachParas['billSplitOfOwner']
  228. owner_split['merchantId'] = owner_split.pop('splitBillMerchantEmail')
  229. owner_split['money'] = owner_split.pop('splitBillAmount')
  230. split_map = {
  231. PARTITION_ROLE.OWNER: [owner_split],
  232. PARTITION_ROLE.AGENT: [],
  233. PARTITION_ROLE.PARTNER: []
  234. }
  235. for spliter in self.paySubOrder.attachParas['billSplitList']:
  236. spliter['merchantId'] = spliter.pop('splitBillMerchantEmail')
  237. spliter['money'] = spliter.pop('splitBillAmount')
  238. if spliter['role'] == PARTITION_ROLE.AGENT:
  239. split_map[PARTITION_ROLE.AGENT].append(spliter)
  240. elif spliter['role'] == PARTITION_ROLE.PARTNER:
  241. split_map[PARTITION_ROLE.PARTNER].append(spliter)
  242. else:
  243. raise UserServerException(u'错误的分账角色')
  244. else:
  245. owner_split = self.paySubOrder.attachParas['billSplitOfOwner']
  246. owner_split['merchantId'] = owner_split.pop('splitBillMerchantEmail')
  247. owner_split['money'] = owner_split.pop('splitBillAmount')
  248. split_map = {
  249. PARTITION_ROLE.OWNER: [owner_split],
  250. PARTITION_ROLE.AGENT: [],
  251. PARTITION_ROLE.PARTNER: []
  252. }
  253. else:
  254. split_map = proxy.partition_map
  255. refund_income_order = self.paySubOrder.issue_refund_income_order(
  256. self.refundOrder, split_map) # type: RechargeRecord
  257. succeed = self.refundOrder.retry_processing(
  258. changeOrderNo = (not self.refundOrder.is_no_order) and self.refundOrder.pay_app_type in [PayAppType.JD_OPEN])
  259. if not succeed:
  260. logger.info(
  261. 'refund ignored. refund orderNo = {} reason = unique check failure.'.format(self.refundOrder.orderNo))
  262. return
  263. self.refundOrder.reload()
  264. frozen_callable(self.refundOrder)
  265. try:
  266. self.submit_refund(
  267. self.refundOrder, refund_income_order.partition_map, u'现金退款',
  268. notify_url or self.refundOrder.notify_url, refund_callable)
  269. except Exception:
  270. import traceback
  271. logger.warning(
  272. 'Refund request failure! orderNo = {}; e = {}'.format(self.refundOrder, traceback.format_exc()))
  273. finally:
  274. self.refundOrder.reload()
  275. if self.refundOrder.is_closed or self.refundOrder.is_success:
  276. # 终态已经调用了post_pay, 所以不在做任何处理
  277. pass
  278. elif self.refundOrder.my_payment_gateway.occupant.role == ROLE.agent:
  279. # 资金池情况下认为成功, 冻结运营商金额
  280. if refund_income_order.result != RechargeRecord.PayResult.SUCCESS:
  281. refund_income_order.result = RechargeRecord.PayResult.SUCCESS
  282. refund_income_order.finishedTime = datetime.datetime.now()
  283. refund_income_order.save()
  284. if not refund_income_order.is_ledgered:
  285. from apps.web.report.ledger import Ledger
  286. ledger = Ledger(USER_RECHARGE_TYPE.REFUND_CASH, refund_income_order)
  287. ledger.execute(journal = False, stats = True, check = False)
  288. return self.refundOrder
  289. def refund_post_pay(refundOrder, success):
  290. # type: (RefundMoneyRecord, bool)->None
  291. try:
  292. refund_income_order = refundOrder.refund_income_order # type: RechargeRecord
  293. try:
  294. refPay = refund_income_order.extraInfo['refPay']
  295. if isinstance(refund_income_order.extraInfo['refPay'], dict):
  296. refund_income_order.extraInfo['refPay'] = ObjectId(refPay.pop('objId'))
  297. refund_income_order.save()
  298. except:
  299. pass
  300. if success:
  301. refund_success_callback(refundOrder, refundOrder.finishedTime, refund_income_order)
  302. else:
  303. refund_fail_callback(refundOrder, refundOrder.finishedTime, refund_income_order)
  304. except Exception:
  305. import traceback
  306. logger.warning(
  307. 'Refund callback failure. orderNo = {}; e = {}'.format(refundOrder.orderNo, traceback.format_exc()))
  308. def refund_success_callback(refundOrder, finishedTime, refund_income_order):
  309. # type: (RefundMoneyRecord, datetime, RechargeRecord)->None
  310. rechargeOrder = refundOrder.pay_sub_order
  311. if rechargeOrder.via in [USER_RECHARGE_TYPE.RECHARGE, USER_RECHARGE_TYPE.RECHARGE_CASH]:
  312. refundOrder.user.commit_refund_cash(refundOrder)
  313. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_CARD:
  314. if rechargeOrder.attachParas.get('terminalRecharge', False):
  315. pass
  316. else:
  317. card = Card.objects(id = rechargeOrder.attachParas['cardId']).first() # type: Card
  318. card.clear_frozen_balance(card.freeze_transaction_id('r'), VirtualCoin(0))
  319. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD:
  320. userVirtualCard = UserVirtualCard.objects(id = rechargeOrder.attachParas['cardId']).first()
  321. userVirtualCard.commit_refund(refundOrder)
  322. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE:
  323. pass
  324. else:
  325. logger.debug('via({}) is not support.'.format(rechargeOrder.via))
  326. return
  327. if not refund_income_order.is_ledgered: # 记录收益
  328. refund_income_order.finishedTime = finishedTime
  329. refund_income_order.result = RechargeRecord.PayResult.SUCCESS
  330. refund_income_order.save()
  331. from apps.web.report.ledger import Ledger
  332. ledger = Ledger(refund_income_order.via, refund_income_order)
  333. ledger.execute(stats=True)
  334. else:
  335. # FIX预扣单状态.不是SUCCESS先改成SUCCESS
  336. if refund_income_order.result != RechargeRecord.PayResult.SUCCESS:
  337. refund_income_order.finishedTime = refund_income_order.dateTimeAdded
  338. refund_income_order.result = RechargeRecord.PayResult.SUCCESS
  339. refund_income_order.save()
  340. for item in rechargeOrder.extraInfo['refRefund']:
  341. if 'deductId' in item:
  342. if str(item['deductId']) == str(refund_income_order.id):
  343. item['status'] = RefundMoneyRecord.Status.SUCCESS
  344. item['finishedTime'] = refundOrder.finishedTime
  345. rechargeOrder.save()
  346. break
  347. elif str(item['objId']) == str(refund_income_order.id):
  348. item['status'] = RefundMoneyRecord.Status.SUCCESS
  349. item['deductId'] = ObjectId(item.pop('objId'))
  350. item['finishedTime'] = refundOrder.finishedTime
  351. rechargeOrder.save()
  352. break
  353. def refund_fail_callback(refundOrder, finishedTime, refund_income_order):
  354. rechargeOrder = refundOrder.pay_sub_order
  355. if rechargeOrder.via in [USER_RECHARGE_TYPE.RECHARGE, USER_RECHARGE_TYPE.RECHARGE_CASH]:
  356. user = refundOrder.pay_sub_order.myuser # type: MyUser
  357. user.revoke_refund_cash(refundOrder)
  358. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_CARD:
  359. if rechargeOrder.attachParas.get('terminalRecharge', False):
  360. pass
  361. else:
  362. card = Card.objects(id = rechargeOrder.attachParas['cardId']).first()
  363. if not card:
  364. raise UserServerException(u'充值卡不存在')
  365. card.recover_frozen_balance(transaction_id = card.freeze_transaction_id('r'), fee = refundOrder.deductCoins)
  366. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD:
  367. userVirtualCard = UserVirtualCard.objects(id = rechargeOrder.attachParas['cardId']).first()
  368. if not userVirtualCard:
  369. raise UserServerException(u'虚拟卡不存在')
  370. userVirtualCard.revoke_refund(refundOrder)
  371. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE:
  372. monthlyPackage = MonthlyPackage.objects(id = rechargeOrder.attachParas['cardId']).first()
  373. if not monthlyPackage:
  374. raise UserServerException(u'包月套餐不存在')
  375. monthlyPackage.toggle_disable(isDisable = 0)
  376. else:
  377. raise UserServerException(u'不支持的退款订单类型')
  378. if refund_income_order.is_ledgered:
  379. # 如果已经扣款分账则建立一个退单收益单
  380. # FIX预扣单状态.不是SUCCESS先改成SUCCESS
  381. if refund_income_order.result != RechargeRecord.PayResult.SUCCESS:
  382. refund_income_order.finishedTime = refund_income_order.dateTimeAdded
  383. refund_income_order.result = RechargeRecord.PayResult.SUCCESS
  384. refund_income_order.save()
  385. revoke_income_order = refund_income_order.issue_refund_revoke_order()
  386. from apps.web.report.ledger import Ledger
  387. ledger = Ledger(DEALER_INCOME_SOURCE.REVOKE_REFUND_CASH, revoke_income_order)
  388. ledger.execute(journal = False, stats = True, check = False)
  389. for item in rechargeOrder.extraInfo['refRefund']:
  390. if 'deductId' in item:
  391. if str(item['deductId']) == str(refund_income_order.id):
  392. item['status'] = RefundMoneyRecord.Status.CLOSED
  393. item['revokeId'] = revoke_income_order.id
  394. item['finishedTime'] = refundOrder.finishedTime
  395. rechargeOrder.save()
  396. break
  397. elif str(item['objId']) == str(refund_income_order.id):
  398. item['status'] = RefundMoneyRecord.Status.CLOSED
  399. item['deductId'] = ObjectId(item.pop('objId'))
  400. item['revokeId'] = revoke_income_order.id
  401. item['finishedTime'] = refundOrder.finishedTime
  402. rechargeOrder.save()
  403. break
  404. else:
  405. refund_income_order.finishedTime = finishedTime
  406. refund_income_order.result = RechargeRecord.PayResult.CANCEL
  407. refund_income_order.save()
  408. for item in rechargeOrder.extraInfo['refRefund']:
  409. if 'deductId' in item:
  410. if str(item['deductId']) == str(refund_income_order.id):
  411. item['status'] = RefundMoneyRecord.Status.CLOSED
  412. item['finishedTime'] = refundOrder.finishedTime
  413. rechargeOrder.save()
  414. break
  415. elif str(item['objId']) == str(refund_income_order.id):
  416. item['status'] = RefundMoneyRecord.Status.CLOSED
  417. item['deductId'] = item.pop('objId')
  418. item['finishedTime'] = refundOrder.finishedTime
  419. rechargeOrder.save()
  420. break
  421. def frozen_refund_func(refundOrder):
  422. # type: (RefundMoneyRecord)->None
  423. """
  424. :param refundOrder:
  425. :return:
  426. """
  427. rechargeOrder = refundOrder.pay_sub_order
  428. if rechargeOrder.via in [USER_RECHARGE_TYPE.RECHARGE, USER_RECHARGE_TYPE.RECHARGE_CASH]:
  429. user = refundOrder.pay_sub_order.myuser
  430. if not user:
  431. raise UserServerException(u'用户不存在')
  432. minus_total_consume = VirtualCoin(refundOrder.extraInfo.get('minus_total_consume', 0))
  433. deduct_coins = refundOrder.deductCoins
  434. frozen_coins = refundOrder.frozenCoins
  435. logger.debug('MyUser<id={}> prepare refund cash. money = {}, coins = {}, before = {}'.format(
  436. str(user.id), refundOrder.money, deduct_coins, user.balance
  437. ))
  438. user.prepare_refund_cash(refundOrder, deduct_coins, frozen_coins, minus_total_consume)
  439. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_CARD:
  440. if rechargeOrder.attachParas.get('terminalRecharge', False):
  441. logger.debug('Card<id={}> prepare refund cash. money = {}'.format(
  442. 'terminalRecharge', refundOrder.money
  443. ))
  444. else:
  445. card = Card.objects(id = rechargeOrder.attachParas['cardId']).first()
  446. if not card:
  447. raise UserServerException(u'充值卡不存在')
  448. logger.debug('Card<id={}> prepare refund cash. money = {}, coins = {}, before = {}'.format(
  449. str(card.id), refundOrder.money, refundOrder.deductCoins, card.balance
  450. ))
  451. card.freeze_balance(transaction_id = card.freeze_transaction_id('r'), fee = refundOrder.deductCoins)
  452. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_VIRTUAL_CARD:
  453. userVirtualCard = UserVirtualCard.objects(id=rechargeOrder.attachParas['cardId']).first()
  454. if not userVirtualCard:
  455. raise UserServerException(u'虚拟卡不存在')
  456. userVirtualCard.prepare_refund(refundOrder)
  457. elif rechargeOrder.via == USER_RECHARGE_TYPE.RECHARGE_MONTHLY_PACKAGE:
  458. monthlyPackage = MonthlyPackage.objects(id = rechargeOrder.attachParas['cardId']).first()
  459. if not monthlyPackage:
  460. raise UserServerException(u'包月套餐不存在')
  461. monthlyPackage.toggle_disable(isDisable = 1)
  462. else:
  463. logger.debug('via({}) is not support.'.format(rechargeOrder.via))