ywt_chongdiangui.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import sys
  4. # noinspection PyUnresolvedReferences
  5. from pandas import Interval
  6. from apps.web.constant import Const
  7. from apps.web.device.models import DevicePortReport
  8. class DefaultParams(object):
  9. STATUS_MAP = {
  10. "00": Const.DEV_WORK_STATUS_IDLE,
  11. "01": Const.DEV_WORK_STATUS_WORKING,
  12. "02": Const.DEV_WORK_STATUS_OCCUPY,
  13. "03": Const.DEV_WORK_STATUS_FAULT, # 故障
  14. "04": Const.DEV_WORK_STATUS_FAULT, # 烟感
  15. "05": Const.DEV_WORK_STATUS_FAULT, # 雨感
  16. "06": Const.DEV_WORK_STATUS_FAULT # 设备锁定
  17. }
  18. FAULT_MAP = {
  19. "1001": u"烟雾报警",
  20. "1002": u"雨感报警",
  21. "1003": u"温度报警"
  22. }
  23. STOP_REASON_MAP = {
  24. "00": "充满自停",
  25. "01": "未检测到充电设备",
  26. "02": "过载结束",
  27. "03": "电压输出故障",
  28. "04": "刷卡结束",
  29. "05": "充满自停",
  30. "06": "密码开锁结束订单"
  31. }
  32. DEFAULT_MIN_START_COINS = 2
  33. DEFAULT_MIN_POWER = 20
  34. DEFAULT_MAX_POWER = 500
  35. DEFAULT_FLOAT_TIME = 2
  36. DEFAULT_IC_CODE = "0001"
  37. DEFAULT_PORT_NUM = 10
  38. # 计费相关
  39. DEFAULT_CHARGE_TYPE = "time"
  40. # DEFAULT_MIN_CARD_MONEY = DEFAULT_MIN_START_COINS
  41. DEFAULT_MIN_CONSUME = 1.0
  42. DEFAULT_MAX_CONSUME = 20.0
  43. DEFAULT_STAY_TIME_UNIT_PRICE = 0.5
  44. DEFAULT_FREE_STAY_TIME = 5
  45. DEFAULT_TIME_UNIT_PRICE = 1
  46. DEFAULT_POWER_PACKAGE = [
  47. {
  48. "lowLimit": 20,
  49. "upLimit": 250,
  50. "price": 1,
  51. "time": 180,
  52. },
  53. {
  54. "lowLimit": 250,
  55. "upLimit": 360,
  56. "price": 1,
  57. "time": 120
  58. },
  59. {
  60. "lowLimit": 360,
  61. "upLimit": 500,
  62. "price": 1,
  63. "time": 60,
  64. }
  65. ]
  66. class Calculater(object):
  67. """
  68. 计费 策略类 拆分出来实现的比较简单 有时间再重新搞一下
  69. 计费 目前来看 只和 账单 以及 设备有关系
  70. 账单 影响 账面上的钱
  71. 设备影响 账单的其他因素 例如退费保护时间 最低消费 最高消费
  72. 后续配置可能还会涉及到人 比如优惠卷、折扣卷等等
  73. """
  74. def __init__(self, device, order):
  75. self.device = device
  76. self.order = order
  77. chargeType = order.servicedInfo.get("chargeType", "")
  78. strategyClass = getattr(sys.modules[__name__], "{}Strategy".format(chargeType.capitalize()))
  79. self._strategy = strategyClass(self)
  80. @property
  81. def strategy(self):
  82. return self._strategy
  83. @property
  84. def result(self):
  85. # 先计算账单 应该付款的钱
  86. if not self.strategy:
  87. consume = 0
  88. else:
  89. consume = self.strategy.calculate()
  90. # 计算占位费 对于占位费的计算方式都是一样的 时间 * 单价
  91. otherConf = self.device.get("otherConf") or dict()
  92. stayPrice = otherConf.get("stayTimeUnitPrice", DefaultParams.DEFAULT_STAY_TIME_UNIT_PRICE)
  93. consume += (self.stayTime * stayPrice / 60)
  94. # 在看下是否满足最低消费金额 以及最大消费金额
  95. maxConsume = otherConf.get("maxConsume", DefaultParams.DEFAULT_MAX_CONSUME)
  96. minConsume = otherConf.get("minConsume", DefaultParams.DEFAULT_MIN_CONSUME)
  97. return min(max(minConsume, consume), maxConsume)
  98. @property
  99. def stayTime(self):
  100. """
  101. 需要考虑免费占位时间
  102. :return:
  103. """
  104. try:
  105. orderNo = self.order.orderNo
  106. _time = DevicePortReport.last_one(orderNo).stayTime if DevicePortReport.last_one(orderNo) else 0
  107. # 减去免费占位时间
  108. otherConf = self.device.get("otherConf") or dict()
  109. freeStayTime = int(otherConf.get("freeStayTime", DefaultParams.DEFAULT_FREE_STAY_TIME))
  110. # 单位是小时, 这个地方
  111. _time -= (freeStayTime * 60)
  112. except Exception as e:
  113. _time = 0
  114. return max(_time, 0)
  115. class BaseStrategy(object):
  116. def __init__(self, context):
  117. self.context = context
  118. def calculate(self):
  119. raise NotImplemented(u"尚未实现")
  120. class TimeStrategy(BaseStrategy):
  121. def calculate(self):
  122. # 先找到单号 以及 端口号
  123. orderNo = self.context.order.orderNo
  124. reportRecord = DevicePortReport.last_billing_one(orderNo)
  125. chargeTime = reportRecord.chargeTime if reportRecord else 0
  126. # 获取时间计费的单价
  127. otherConf = self.context.device.get("otherConf") or dict()
  128. chargePrice = otherConf.get("timeUnitPrice", DefaultParams.DEFAULT_TIME_UNIT_PRICE)
  129. return chargeTime * chargePrice / 60
  130. class PowerStrategy(BaseStrategy):
  131. def calculate(self):
  132. # 同样的先获取单号
  133. # 获取功率的套餐
  134. orderNo = self.context.order.orderNo
  135. otherConf = self.context.device.get("otherConf") or dict()
  136. powerPackage = otherConf.get("powerPackage", DefaultParams.DEFAULT_POWER_PACKAGE)
  137. # 区间结构
  138. mapDict = dict()
  139. for package in powerPackage:
  140. lowLimit = package.get("lowLimit")
  141. upLimit = package.get("upLimit")
  142. price = package.get("price")
  143. _time = package.get("time")
  144. mapDict.update({
  145. Interval(int(lowLimit), int(upLimit), closed="left"):
  146. {
  147. "unitPrice": float(price) / float(_time),
  148. "time": 0
  149. }
  150. })
  151. powerRecords = DevicePortReport.billing_records(orderNo)
  152. return DevicePortReport.calculate(powerRecords, mapDict)