123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- # -*- coding: utf-8 -*-
- #!/usr/bin/env python
- import datetime
- import logging
- from apilib.monetary import RMB, VirtualCoin, Ratio
- from apilib.utils_datetime import to_datetime
- from apps.web.constant import DEALER_CONSUMPTION_AGG_KIND
- from apps.web.device.models import Device, Group
- from apps.web.eventer.base import WorkEvent
- from apps.web.eventer import EventBuilder
- from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, MyUser, ConsumeRecord
- logger = logging.getLogger(__name__)
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- if device_event['cmd'] == 100:
- event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
- return DeKangEvent(self.deviceAdapter, event_data)
- return None
-
- class DeKangEvent(WorkEvent):
- def __init__(self, smartBox, event_data):
- super(DeKangEvent, self).__init__(smartBox, event_data)
- def do(self, **args):
- """
- 状态:
- 00 : 未插 空闲 AA5524019B010000000008CA000000 00 000000000000000000000000000000000000000000B409BB
- 11 : 插上 检测负载 AA5524019B010000000008CA000000 11 0000000000000000000000000000000000000000002AD9BB
- 12 : 付款 继电器连接 AA5524019B01000000000000043B3B 12 1400000000000000000000000000000000000000003401BB
- 13 : 付款 继电器断开 AA5524019B010000000025D404330B 13 1400000000000000000000000000000000000000005529BB
- 52 : 启动 使用 AA5524019B01000000000000043B3A 52 14000000000000000000000000000000000000000065B1BB
- :param args:
- :return:
- """
- devNo = self.device['devNo']
- portStatus = self.event_data.get('portStatus')
- portStr = self.event_data.pop('portStr')
- if portStatus in ['0000', '0001', '0100']: # 0000:未插空闲 (拔插头) #0001 负载接入状态 #0100 充电完成
- self.do_finished_or_update_cache(portStr)
- elif portStatus in ['0010', '0011']:
- portInfo = Device.get_dev_control_cache(devNo).get(portStr, {})
- needTime = portInfo.get('needTime') # 第一次上报初始化一个最大时间
- if not needTime:
- portInfo.update({'needTime': self.event_data.get('leftTime')})
- portInfo.update(self.event_data)
- Device.update_dev_control_cache(devNo, {portStr: portInfo})
- else:
- logger.error('undefine port status! dev: %s port: %s status: %s' % (devNo, portStr, portStatus))
- def do_finished_or_update_cache(self, portStr):
- devNo = self.device.devNo
- lineInfo = Device.get_dev_control_cache(devNo).get(portStr, {})
-
- orderNo = lineInfo.get('orderNo')
- if not self.check_order_status(orderNo):
- # 主板切换到状态 却没有 缓存信息 说明是 启动用户 否则则为 结束用户
- Device.clear_port_control_cache(devNo, portStr)
- Device.update_port_control_cache(devNo, self.event_data)
- logger.info('devNo=<{}> port=<{}> data={}> now do Cache updating'.format(devNo, portStr, self.event_data))
- return
- openId = lineInfo.get('openId')
- coins = VirtualCoin(lineInfo['coins'])
- price = RMB(lineInfo['price'])
-
-
- actualNeedTime = lineInfo.get('needTime') # 总共需要时间
- if not actualNeedTime:
- Device.clear_port_control_cache(devNo, portStr)
- Device.update_port_control_cache(devNo, self.event_data)
- return
-
- startTime = to_datetime(lineInfo['startTime'])
- nowTime = datetime.datetime.now()
- usedTime = ((nowTime - startTime).total_seconds() + 59) / 60
- if usedTime > actualNeedTime:
- usedTime = actualNeedTime
-
- leftTime = actualNeedTime - usedTime
- refundProtectionTime = self.device['otherConf'].get('refundProtectionTime', 5)
-
-
- if usedTime <= refundProtectionTime:
- backCoins = VirtualCoin(coins)
- refundRMB = RMB(price)
- else:
- if self.device.is_auto_refund:
- backCoins = coins * Ratio(float(leftTime) / float(actualNeedTime))
- refundRMB = price * Ratio(float(leftTime) / float(actualNeedTime))
- else:
- backCoins = VirtualCoin(0)
- refundRMB = RMB(0)
-
- try:
- title = u'您的充电服务已结束,端口已经断开连接,感谢您的使用! '
- vCardId = lineInfo.get('vCardId', None)
- user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first()
- group = Group.get_group(self.device['groupId'])
- self.notify_user(user.managerialOpenId, 'service_complete',
- **{
- 'title': title,
- 'service': u'充电服务(设备编号:%s,分机:%s,地址:%s)' % (
- self.device['logicalCode'], portStr, group['address']),
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- 'remark': u'谢谢您的支持'
- })
- logger.info('notify user completed!')
-
- # 处理退费!!
- # 扫码支付
- if not vCardId:
- # 服务结束通知
- consumeDict = {
- 'reason': u'充电结束',
- 'needTime': actualNeedTime,
- DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime,
- DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount
- }
-
- logger.info('refund money start!')
-
- if backCoins > VirtualCoin(0) or refundRMB > RMB(0):
- payInfo = lineInfo.get('payInfo')
- refundCash = 'refundRMB_device_event' in self.device.owner.features
- extra = {'title': u'退款通知', 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
- if refundCash and payInfo:
- self.refund_net_pay(user, lineInfo, refundRMB, VirtualCoin(0), consumeDict, True)
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (price - refundRMB).mongo_amount})
- extra.update({'backCount': u'金额:%s' % refundRMB})
- else:
- self.refund_net_pay(user, lineInfo, RMB(0), backCoins, consumeDict, False)
- extra.update({'backCount': u'金币:%s' % backCoins})
-
- # 退款通知
- self.notify_user(user.managerialOpenId, 'refund_coins',**extra)
-
- logger.info('server complete, no money refund!')
-
- # 虚拟卡支付
- else:
- # 通知充电完成
- vCard = UserVirtualCard.objects.filter(id=vCardId).first()
- if not vCard:
- logger.info('devNo=<{}> port=<{}> vCardId=<{}> no this vCard'.format(devNo, portStr, vCardId))
- consumeDict = {
- 'reason': u'充电结束',
- DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime,
- 'actualNeedTime': actualNeedTime,
- }
-
- consumeRcdId = lineInfo.get('consumeRcdId', None)
- if consumeRcdId is None:
- logger.info('can not find consume rcd id')
- return
-
- vCardConsumeRcd = VCardConsumeRecord.objects.filter(id=consumeRcdId).first()
- if not vCardConsumeRcd:
- logger.info('can not find the consume rcd id = %s' % consumeRcdId)
- return
-
- # 消费单位都为次 直接用算好的退币进行退款
- vCard.refund_quota(vCardConsumeRcd, 0, 0, backCoins.mongo_amount)
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {'open_id': openId, 'device_imei': self.device['devNo'], 'port': int(portStr),
- 'isFinished': False},
- consumeDict
- )
-
- except Exception:
- import traceback
- logger.info(traceback.format_exc())
- finally:
- Device.clear_port_control_cache(devNo, portStr)
- Device.update_port_control_cache(devNo, self.event_data)
- def check_order_status(self, orderNo):
- """
- 防重入 和 校验信息
- :param orderNo:
- :return:
- """
- if not orderNo:
- return False
-
- order = ConsumeRecord.objects.filter(orderNo=orderNo).first()
-
- if not order:
- return False
-
- if order.status == 'finished':
- return False
-
- else:
- order.update(status='finished', finishedTime=datetime.datetime.now())
- return True
|