123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import sys
- # noinspection PyUnresolvedReferences
- from pandas import Interval
- from apps.web.constant import Const
- from apps.web.device.models import DevicePortReport
- class DefaultParams(object):
- STATUS_MAP = {
- "00": Const.DEV_WORK_STATUS_IDLE,
- "01": Const.DEV_WORK_STATUS_WORKING,
- "02": Const.DEV_WORK_STATUS_OCCUPY,
- "03": Const.DEV_WORK_STATUS_FAULT, # 故障
- "04": Const.DEV_WORK_STATUS_FAULT, # 烟感
- "05": Const.DEV_WORK_STATUS_FAULT, # 雨感
- "06": Const.DEV_WORK_STATUS_FAULT # 设备锁定
- }
- FAULT_MAP = {
- "1001": u"烟雾报警",
- "1002": u"雨感报警",
- "1003": u"温度报警"
- }
- STOP_REASON_MAP = {
- "00": "充满自停",
- "01": "未检测到充电设备",
- "02": "过载结束",
- "03": "电压输出故障",
- "04": "刷卡结束",
- "05": "充满自停",
- "06": "密码开锁结束订单"
- }
- DEFAULT_MIN_START_COINS = 2
- DEFAULT_MIN_POWER = 20
- DEFAULT_MAX_POWER = 500
- DEFAULT_FLOAT_TIME = 2
- DEFAULT_IC_CODE = "0001"
- DEFAULT_PORT_NUM = 10
- # 计费相关
- DEFAULT_CHARGE_TYPE = "time"
- # DEFAULT_MIN_CARD_MONEY = DEFAULT_MIN_START_COINS
- DEFAULT_MIN_CONSUME = 1.0
- DEFAULT_MAX_CONSUME = 20.0
- DEFAULT_STAY_TIME_UNIT_PRICE = 0.5
- DEFAULT_FREE_STAY_TIME = 5
- DEFAULT_TIME_UNIT_PRICE = 1
- DEFAULT_POWER_PACKAGE = [
- {
- "lowLimit": 20,
- "upLimit": 250,
- "price": 1,
- "time": 180,
- },
- {
- "lowLimit": 250,
- "upLimit": 360,
- "price": 1,
- "time": 120
- },
- {
- "lowLimit": 360,
- "upLimit": 500,
- "price": 1,
- "time": 60,
- }
- ]
- class Calculater(object):
- """
- 计费 策略类 拆分出来实现的比较简单 有时间再重新搞一下
- 计费 目前来看 只和 账单 以及 设备有关系
- 账单 影响 账面上的钱
- 设备影响 账单的其他因素 例如退费保护时间 最低消费 最高消费
- 后续配置可能还会涉及到人 比如优惠卷、折扣卷等等
- """
- def __init__(self, device, order):
- self.device = device
- self.order = order
- chargeType = order.servicedInfo.get("chargeType", "")
- strategyClass = getattr(sys.modules[__name__], "{}Strategy".format(chargeType.capitalize()))
- self._strategy = strategyClass(self)
- @property
- def strategy(self):
- return self._strategy
- @property
- def result(self):
- # 先计算账单 应该付款的钱
- if not self.strategy:
- consume = 0
- else:
- consume = self.strategy.calculate()
- # 计算占位费 对于占位费的计算方式都是一样的 时间 * 单价
- otherConf = self.device.get("otherConf") or dict()
- stayPrice = otherConf.get("stayTimeUnitPrice", DefaultParams.DEFAULT_STAY_TIME_UNIT_PRICE)
- consume += (self.stayTime * stayPrice / 60)
- # 在看下是否满足最低消费金额 以及最大消费金额
- maxConsume = otherConf.get("maxConsume", DefaultParams.DEFAULT_MAX_CONSUME)
- minConsume = otherConf.get("minConsume", DefaultParams.DEFAULT_MIN_CONSUME)
- return min(max(minConsume, consume), maxConsume)
- @property
- def stayTime(self):
- """
- 需要考虑免费占位时间
- :return:
- """
- try:
- orderNo = self.order.orderNo
- _time = DevicePortReport.last_one(orderNo).stayTime if DevicePortReport.last_one(orderNo) else 0
- # 减去免费占位时间
- otherConf = self.device.get("otherConf") or dict()
- freeStayTime = int(otherConf.get("freeStayTime", DefaultParams.DEFAULT_FREE_STAY_TIME))
- # 单位是小时, 这个地方
- _time -= (freeStayTime * 60)
- except Exception as e:
- _time = 0
- return max(_time, 0)
- class BaseStrategy(object):
- def __init__(self, context):
- self.context = context
- def calculate(self):
- raise NotImplemented(u"尚未实现")
- class TimeStrategy(BaseStrategy):
- def calculate(self):
- # 先找到单号 以及 端口号
- orderNo = self.context.order.orderNo
- reportRecord = DevicePortReport.last_billing_one(orderNo)
- chargeTime = reportRecord.chargeTime if reportRecord else 0
- # 获取时间计费的单价
- otherConf = self.context.device.get("otherConf") or dict()
- chargePrice = otherConf.get("timeUnitPrice", DefaultParams.DEFAULT_TIME_UNIT_PRICE)
- return chargeTime * chargePrice / 60
- class PowerStrategy(BaseStrategy):
- def calculate(self):
- # 同样的先获取单号
- # 获取功率的套餐
- orderNo = self.context.order.orderNo
- otherConf = self.context.device.get("otherConf") or dict()
- powerPackage = otherConf.get("powerPackage", DefaultParams.DEFAULT_POWER_PACKAGE)
- # 区间结构
- mapDict = dict()
- for package in powerPackage:
- lowLimit = package.get("lowLimit")
- upLimit = package.get("upLimit")
- price = package.get("price")
- _time = package.get("time")
- mapDict.update({
- Interval(int(lowLimit), int(upLimit), closed="left"):
- {
- "unitPrice": float(price) / float(_time),
- "time": 0
- }
- })
- powerRecords = DevicePortReport.billing_records(orderNo)
- return DevicePortReport.calculate(powerRecords, mapDict)
|