services.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import copy
  4. import datetime
  5. import json
  6. import logging
  7. from typing import TYPE_CHECKING
  8. from apilib.monetary import RMB
  9. from apilib.utils_string import cn
  10. from apilib.utils_sys import MemcachedLock
  11. from apps.web.constant import START_DEVICE_STATUS
  12. from apps.web.core.exceptions import ServiceException, MqttSubscribeError, ClientServiceTimeOutException
  13. from apps.web.exceptions import UserServerException
  14. from apps.web.user.models import ConsumeRecord
  15. from apps.web.user.utils2 import generate_net_payment, ConsumeOrderStateEngine
  16. from apps.web.utils import set_start_key_status
  17. logger = logging.getLogger(__name__)
  18. if TYPE_CHECKING:
  19. from apps.web.device.models import DeviceDict
  20. from apps.web.user.models import RefundMoneyRecord
  21. # ------------------------ 以下为新增内容 ----------------------------------------------
  22. class PolicyService(object):
  23. def __init__(self, order): # type:(ConsumeRecord) -> None
  24. self._order = order
  25. def handle_verify_order(self):
  26. """
  27. 检验订单
  28. """
  29. # 1. 防止支付超时
  30. if self._order.status != self._order.Status.WAIT_CONF:
  31. raise ServiceException({"result": 2, "description": u"订单状态异常,请前往个人中心查看订单"})
  32. if self._order.isFree:
  33. return
  34. # 2. 对订单用户金额做检验 注意 这个地方不使用免费来跳过 因为免费设置在组级别 而费用设置在套餐级别
  35. balance = self._order.user.calc_currency_balance(
  36. dealer=self._order.owner,
  37. group=self._order.group
  38. )
  39. if balance < RMB(0):
  40. raise ServiceException({"result": 1002, "description": u"当前账户余额不足,请充值后使用"})
  41. # 临时套餐的最小消费金额为0
  42. if balance < self._order.package.minAfterStartCoins:
  43. raise ServiceException({"result": 1002, "description": u"当前套餐账户最小余额为{}元,请充值后使用".format(self._order.package.minAfterStartCoins)})
  44. if self._order.isPostPaid:
  45. return
  46. try:
  47. payment = generate_net_payment(self._order)
  48. except UserServerException as e:
  49. raise ServiceException({"result": 1002, "description": e.message})
  50. return payment
  51. def handle_start_order(self):
  52. """
  53. 执行订单
  54. """
  55. return self._order.device.deviceAdapter.start_device_realiable(self._order)
  56. def handle_account_order(self):
  57. """
  58. 对账单进行扣款动作
  59. """
  60. self._order.frozen_payer_balance()
  61. class StartDeviceEngine(object):
  62. def __init__(self, order): # type:(ConsumeRecord) -> None
  63. self._order = order
  64. self._service = self.__get_service() # type: PolicyService
  65. def __get_service(self):
  66. return PolicyService(self._order)
  67. def get_payment_info(self):
  68. return self._service.handle_verify_order()
  69. def start(self, *args, **kwargs):
  70. try:
  71. set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.RUNNING)
  72. result = self._service.handle_start_order()
  73. self._service.handle_account_order()
  74. ConsumeOrderStateEngine(self._order).to_running(result)
  75. set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.FINISHED)
  76. except ClientServiceTimeOutException:
  77. # 订单超时状态 此状态订单状态未知 有可能被事件服务器拯救
  78. logger.error("[{} start] order = {}, timeout error".format(self.__class__.__name__, self._order.orderNo))
  79. set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.TIMEOUT)
  80. ConsumeOrderStateEngine(self._order).to_timeout(u"网络通信超时")
  81. except ServiceException as serviceErr:
  82. # 订单失败的状态 绝对的失败
  83. errorMsg = serviceErr.result
  84. logger.error("[{} start] order = {}, service error = {}".format(self.__class__.__name__, self._order.orderNo, errorMsg))
  85. set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.FAILURE)
  86. ConsumeOrderStateEngine(self._order).to_failure(u"设备启动异常【{}】".format(errorMsg))
  87. except MqttSubscribeError as mqttErr:
  88. # 订单失败的状态 绝对的失败 该退钱退钱
  89. errorMsg = u'系统忙无响应,您支付的金币已经退还到您的账户。您可以重试,或者选择其他线路或其他设备(不需要再次支付)。'
  90. logger.error("[{} start] order = {}, mqtt error = {}".format(self.__class__.__name__, self._order.orderNo, mqttErr))
  91. set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.FAILURE, reason=cn(errorMsg))
  92. ConsumeOrderStateEngine(self._order).to_failure(u"网络异常")
  93. except Exception as err:
  94. errorMsg = u'启动过程中有异常发生,您支付的金币已经退还到您的账户。'
  95. logger.exception("[{} start] order = {}, error = {}".format(self.__class__.__name__, self._order.orderNo, err))
  96. set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.FAILURE, reason=cn(errorMsg))
  97. ConsumeOrderStateEngine(self._order).to_unknown(u"启动异常")
  98. def wrapper_start_device(locker, proxy, *args, **kwargs):
  99. # type: (MemcachedLock, StartDeviceEngine, list, dict)->None
  100. try:
  101. proxy.start(*args, **kwargs)
  102. finally:
  103. locker.release()