changyuan.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. # -*- coding: utf-8 -*-
  2. import datetime
  3. import logging
  4. from mongoengine import DoesNotExist, ValidationError
  5. from typing import TYPE_CHECKING
  6. from apps.web.constant import USER_RECHARGE_TYPE
  7. from apps.web.core.payment import WithdrawGateway
  8. from apps.web.device.models import Group
  9. from apps.web.report.ledger import Ledger
  10. from apps.web.user.models import Card, RechargeRecord
  11. if TYPE_CHECKING:
  12. from apps.web.device.models import DeviceDict
  13. logger = logging.getLogger(__name__)
  14. class CYConstant(object):
  15. FINISH_REASON_MAP = {
  16. '01': '充满电停止',
  17. '02': '超功率停止',
  18. '03': '时间用完停止',
  19. '04': '远程停止',
  20. '05': '预付卡的扣费金额用完',
  21. '06': '到达安全充电时间',
  22. '07': '正常结束充电',
  23. '09': '电量超限',
  24. '10': '设备充满停止充电'
  25. }
  26. NEED_REFUND = ["01", "04", "05", "06", "07", "10"]
  27. DEFAULT_DISCOUNT = "0"
  28. REFUND_PRODUCTION_TIME = 5
  29. MAX_TEMPERATURE = 70
  30. MIN_TEMPERATURE = -15
  31. class FunCode(object):
  32. # 发送设备事件
  33. GET_SETTING = "A0"
  34. SET_SETTING = "A1"
  35. GET_DEV_INFO = "A2"
  36. CLEAN_DEV_INFO = "A3"
  37. REFUND_RECORD = "A4"
  38. CHARGE_RECORD = "A5"
  39. CHECK_DEV_STATUS = "A6"
  40. WEIXIN_PAY_START = "A7"
  41. START_OR_STOP = "A9"
  42. CARD_RECHARGR = "AC"
  43. CARD_BALANCE = "AD"
  44. STOP_DEV = "AF"
  45. RESTART = "B0"
  46. class CmdCode(object):
  47. # 设备上报事件
  48. CARD_REFUND = "B3"
  49. STOP_DEV = "A8"
  50. DEV_CONNECTED = "AE"
  51. CARD_PAY_START = "B1"
  52. HEART_BEAT = "B2"
  53. class CYCardMixin(object):
  54. if TYPE_CHECKING:
  55. @property
  56. def device(self):
  57. # type:()->DeviceDict
  58. return DeviceDict()
  59. def notify_dealer(self, templateName, **kwargs):
  60. pass
  61. def check_card_can_use(self, card): # type:(Card) -> bool
  62. """
  63. 对于平台卡检验 的判定
  64. 返回结果是可用或者不可用
  65. 注意: 卡是否录入是以经销商录入为标准判定
  66. 规则是:
  67. 1.如果校验开关关闭 则都是可用的
  68. 2.如果校验开关打开 卡录入情况下可用 卡没有录入的情况下不可用
  69. """
  70. needBindCard = self.device.otherConf.get("needBindCard", True)
  71. if not needBindCard:
  72. return True
  73. # 剩下的是需要检验的情况
  74. # 1. 没有绑定
  75. if not card:
  76. return False
  77. # 2. 解除了绑定(经销商绑定的卡会通过检验 经销商绑定的卡是 匿名用户的openId)
  78. if not card.openId:
  79. return False
  80. # 3. 卡被冻结
  81. if card.frozen:
  82. return False
  83. # 4. 地址不通用的情况
  84. if not Group.is_currency_mode_group(card.groupId, self.device.groupId):
  85. return False
  86. return True
  87. def update_card_dealer_and_type(self, cardNo, cardType='IC', isHaveBalance=True, balance=None):
  88. """
  89. 从数据库找卡 主要功能是为没有卡类型的卡添加上卡的类型
  90. 昌原的卡比较特别 如果是数据库的卡 一定会有dealerId
  91. """
  92. from apps.web.agent.models import Agent
  93. dealer = self.device.owner
  94. agent = Agent.objects(id = dealer.agentId).first() # type: Agent
  95. if not agent:
  96. logger.error('agent is not found, agentId=%s' % dealer.agentId)
  97. return None
  98. try:
  99. card = Card.objects.get(cardNo=cardNo, agentId=str(agent.id))
  100. # 存在卡的类型 说明已经在数据库中了
  101. if card.cardType:
  102. return card
  103. card.devNo = card.devNo or self.device.devNo
  104. card.cardType = card.cardType or cardType
  105. card.isHaveBalance = isHaveBalance
  106. return card.save()
  107. except DoesNotExist:
  108. return None
  109. except Exception as e:
  110. logger.error("[CYCardMixin update_card_dealer_and_type] find card error = {}, dev = {}".format(e, self.device.devNo))
  111. return None
  112. def notify_invalid_card_to_dealer(self, cardNo, card):
  113. logger.info('[CYCardMixin notify_invalid_card_to_dealer] Illegal card <{}>, charging is about to stop'.format(cardNo))
  114. self.notify_dealer(
  115. 'device_fault',
  116. title=u'您当前的设备已被非法卡使用!',
  117. device=u'设备{}-{}'.format(self.device.logicalCode, self.device.groupNumber),
  118. location=u'地址{}-{}'.format(self.device.group.address, self.device.group.groupName),
  119. fault="启动卡号为:{} 卡联系人 {} 卡联系电话 {}".format(
  120. cardNo, card.nickName if card else "", card.phone if card else ""
  121. ),
  122. notifyTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  123. )
  124. def do_ledger(self, rechargeRcdId):
  125. logger.info("[{} do_ledger] rechargeId = {}, devNo= {}".format(self.__class__.__name__, rechargeRcdId, self.device.devNo))
  126. if not rechargeRcdId:
  127. return
  128. record = RechargeRecord.objects(id = rechargeRcdId).first() # type: RechargeRecord
  129. if not record:
  130. logger.error("dev <{}> don't get a recharge record by id <{}>".format(self.device.devNo, rechargeRcdId))
  131. return
  132. if not record.is_success():
  133. logger.debug('{} state is {}.'.format(str(record), record.result))
  134. raise ValueError(u'订单不能为未支付状态')
  135. try:
  136. if record.is_ledgered:
  137. logger.debug('{} has been ledgered.'.format(str(record)))
  138. return record
  139. ledgerTime = None if (
  140. not WithdrawGateway.is_ledger(record.withdraw_source_key)) else datetime.datetime.now()
  141. ledger = Ledger(USER_RECHARGE_TYPE.RECHARGE, record, ledgerTime=ledgerTime)
  142. ledger.execute(stats=True)
  143. except DoesNotExist as de:
  144. logger.error("dev <{}> don't get a recharge record by id <{}>".format(self.device.devNo, rechargeRcdId))
  145. return
  146. except ValidationError as ve:
  147. logger.error("dev <{}> bad a recharge record id <{}>".format(self.device.devNo, rechargeRcdId))
  148. return
  149. except Exception as e:
  150. logger.exception(e)
  151. return
  152. # 执行分账成功的情况下 将充值订单返回
  153. return record