123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import logging
- from apilib.monetary import RMB, VirtualCoin
- from apilib.utils_sys import memcache_lock
- from apps.web.constant import Const
- from apps.web.core.device_define.yongxin import REASON_MAP
- from apps.web.device.models import Group, Device
- from apps.web.eventer import EventBuilder
- from apps.web.eventer.base import WorkEvent
- from apps.web.helpers import device_lock_key
- from apps.web.user.models import ServiceProgress, MyUser, Card, ConsumeRecord, CardConsumeRecord
- logger = logging.getLogger(__name__)
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
- if event_data is None or 'cmdCode' not in event_data:
- return None
- if event_data['cmdCode'] in ['17', '19', '1D', '41', '11']:
- return YongxinWorkEvent(self.deviceAdapter, event_data)
- return None
- class YongxinWorkEvent(WorkEvent):
- def do(self, **args):
- devNo = self.device['devNo']
- logger.info('yong xin car charging event detected, devNo=%s,curInfo=%s' % (devNo, self.event_data))
- if self.event_data["cmdCode"] == "11":
- self.do_login()
- elif self.event_data["cmdCode"] == "41":
- self.do_elec_price()
- elif self.event_data['cmdCode'] == '17': # 刷卡消费上报,需要记录下
- self.do_card_start()
- elif self.event_data['cmdCode'] == '19': # 充电实时数据;分扫码扣费,刷卡扣费
- self.do_report()
- elif self.event_data['cmdCode'] == '1D': # 订单上传,这里需要过滤掉,防止多次报文上报上来
- self.do_finish()
- else:
- logger.error("error cmd, cmd = <{}>, dev = <{}> , event data is <{}>".format(
- self.event_data["cmdCode"],
- self.device.devNo,
- self.event_data
- ))
- return
- def do_card_start(self):
- """
- 处理账单上传
- """
- sequanceNo = self.event_data["sequanceNo"]
- with memcache_lock(key = device_lock_key(self.event_data['cardNo']), value = sequanceNo,
- expire = 360) as acquired:
- if not acquired:
- return
- cardNo = self.event_data['cardNo']
- portStr = str(self.event_data["port"])
- balance = RMB(self.event_data["balance"])
- card = self.update_card_dealer_and_type(cardNo, 'IC', True)
- self.update_card_balance(card, RMB(self.event_data['balance']))
- order = ConsumeRecord.objects(sequanceNo=sequanceNo).first() # type: ConsumeRecord
- # 存在订单的情况下 直接回复就好了 可能是重复性报文
- if order:
- lineInfo = Device.get_port_control_cache(self.device.devNo, self.event_data['port'])
- old_orderNo = lineInfo.get('orderNo', '')
- if lineInfo.get('cardId', '') == str(card.id) and old_orderNo == order.orderNo:
- return self.device.deviceAdapter._response_card_start(portStr, sequanceNo)
- else:
- orderNo, cardOrderNo = self.add_record_consume_for_card(card, sequanceNo, balance)
- # 记录当前服务的progress
- ServiceProgress.register_card_service(self.device, self.event_data['port'], card, {'orderNo': orderNo, 'cardOrderNo': cardOrderNo})
- rv = {
- 'cardId': str(card.id),
- 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- 'isStart': True,
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'useType': 'card',
- 'orderNo': orderNo,
- 'sequanceNo': sequanceNo,
- 'openId': card.openId,
- 'cardNo': self.event_data['cardNo'],
- 'balance': self.event_data['balance']
- }
- Device.update_dev_control_cache(self.device.devNo, {portStr: rv})
- return self.device.deviceAdapter._response_card_start(portStr, sequanceNo)
- def do_report(self):
- """
- 处理 充电数据上传
- """
- lineInfo = Device.get_port_control_cache(self.device.devNo, str(self.event_data["port"]))
- lineInfo.update(self.event_data)
- if not lineInfo.has_key('useType'): # 有可能实时数据先于刷卡数据过来
- return
- if lineInfo['useType'] == 'card': # 刷卡,直接返回就Ok
- servicedInfo = {
- 'outputVoltage': lineInfo['outputVoltage'],
- 'outputElec': lineInfo['outputElec'],
- 'elec': lineInfo['elec'],
- 'spendMoney': lineInfo['spendMoney'],
- 'duration': lineInfo['duration']
- }
- self.update_card_consume_record(
- orderNo=lineInfo['orderNo'],
- spendMoney=lineInfo['spendMoney'],
- desc=u'已经花费%s元,已充%s分钟,%s度电' % (
- lineInfo['spendMoney'], lineInfo['duration'], lineInfo['elec']),
- servicedInfo=servicedInfo
- )
- else:
- # 更新消费信息即可
- leftMoney = str(VirtualCoin(lineInfo.get("coins", 0)) - VirtualCoin(lineInfo["spendMoney"]))
- lineInfo["leftMoney"] = leftMoney
- Device.update_dev_control_cache(self.device.devNo, {str(self.event_data["port"]): lineInfo})
- def do_finish(self):
- """
- 处理 结算账单上传
- """
- sequanceNo = self.event_data['sequanceNo']
- portStr = str(self.event_data["port"])
- with memcache_lock(key = device_lock_key(sequanceNo), value = sequanceNo, expire = 360) as acquired:
- if not acquired:
- return
- self.device.deviceAdapter._response_finished(portStr, sequanceNo, 0)
- order = ConsumeRecord.objects(sequanceNo=sequanceNo).first() # type: ConsumeRecord
- if not order:
- logger.warning('order<no={}> is not exists.'.format(sequanceNo))
- return
- if order.remarks == u'刷卡消费':
- servicedInfo = {
- 'elec': self.event_data['elec'],
- 'spendMoney': self.event_data['spendMoney'],
- 'duration': self.event_data['duration']
- }
- _, cardConsumeRecord = self.update_card_consume_record(
- orderNo=order.orderNo,
- spendMoney=self.event_data['spendMoney'],
- desc=u'一共花费%s元,共充电%s分钟,消耗%s度电' % (
- self.event_data['spendMoney'],
- self.event_data['duration'],
- self.event_data['elec']),
- servicedInfo=servicedInfo
- )
- try:
- cardId = cardConsumeRecord.cardId
- card = Card.objects.get(id=cardId)
- card.balance = RMB(self.event_data['balance'])
- card.save()
- except Exception as e:
- logger.exception('some error=%s' % e)
- else:
- devCache = Device.get_dev_control_cache(self.device.devNo)
- portCache = devCache.get(portStr, {})
- payMoney = VirtualCoin(portCache["coins"])
- spendMoney = VirtualCoin(self.event_data["spendMoney"])
- refundMoney = payMoney - spendMoney
- logger.info("[YONG XIN device <{}> refund money is <{}>]".format(self.device.devNo, refundMoney))
- # 退款大于起始 的情况下 走售后
- if refundMoney > payMoney:
- refundMoney = VirtualCoin(0)
- group = Group.get_group(self.device['groupId'])
- user = order.user
- # 更新用户的余额以及此次的消费金额
- user.balance += RMB(refundMoney)
- order.coin = VirtualCoin(spendMoney)
- order.save()
- user.save()
- consumeDict = {
- 'chargeIndex': self.event_data['port'],
- 'elec': self.event_data['elec'],
- 'spendMoney': self.event_data['spendMoney'],
- 'duration': self.event_data['duration'],
- 'reason': REASON_MAP.get(self.event_data["reason"], "")
- }
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {
- 'open_id': order.openId,
- 'device_imei': self.device['devNo'],
- 'port': self.event_data['port'],
- 'isFinished': False
- },
- consumeDict
- )
- self.notify_user(
- managerialOpenId=user.managerialOpenId if user else "",
- templateName="service_complete",
- title=u"\\n\\n结束原因:\\t\\t{reason}\\n\\n设备编号:\\t\\t{logicalCode}-{port}\\n\\n服务地址:\\t\\t{group}\\n\\n充电时间:\\t\\t{duration}分钟\\n\\n消耗电量:\\t\\t{elec}度".format(
- reason=REASON_MAP.get(self.event_data["reason"], ""),
- logicalCode=self.device["logicalCode"],
- port=self.event_data["port"],
- group=group["address"],
- duration=self.event_data['duration'],
- elec=self.event_data['elec']
- ),
- service=u"充电桩充电服务",
- finishTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- remark=u'谢谢您的支持'
- )
- Device.clear_port_control_cache(self.device.devNo, portStr)
- def do_login(self):
- """
- 处理登录请求
- """
- self.device.deviceAdapter._response_login(self.event_data["devType"])
- def do_elec_price(self):
- """
- 处理电价查询
- """
- self.device.deviceAdapter._response_elec_price()
- def add_record_consume_for_card(self, card, sequanceNo, balance):
- servicedInfo = {}
- group = Group.get_group(self.device['groupId'])
- address = group['address']
- group_number = self.device['groupNumber']
- now = datetime.datetime.now()
- orderNo = ConsumeRecord.make_no()
- new_record = {
- 'orderNo': orderNo,
- 'dateTimeAdded': now,
- 'openId': card.openId,
- 'ownerId': self.device['ownerId'],
- 'coin': VirtualCoin('0.00').mongo_amount,
- 'money': RMB('0.00').mongo_amount,
- 'devNo': self.device['devNo'],
- 'logicalCode': self.device['logicalCode'],
- 'groupId': self.device['groupId'],
- 'address': address,
- 'groupNumber': group_number,
- 'groupName': group['groupName'],
- 'devTypeCode': self.device.devTypeCode,
- 'devTypeName': self.device.devTypeName,
- 'isNormal': True,
- 'status': ConsumeRecord.Status.RUNNING,
- 'remarks': u'刷卡消费',
- 'errorDesc': '',
- 'sequanceNo': sequanceNo,
- 'desc': "",
- 'attachParas': {},
- 'servicedInfo': {}
- }
- ConsumeRecord.get_collection().insert_one(new_record)
- # 刷卡消费也记录一条数据
- cardOrderNo = CardConsumeRecord.make_no()
- if not CardConsumeRecord.objects.filter(devNo = self.device['devNo'], orderNo=orderNo).count():
- new_card_record = {
- 'orderNo': cardOrderNo,
- 'openId': card.openId,
- 'cardId': str(card.id),
- 'money': RMB('0.00').mongo_amount,
- 'balance': balance.mongo_amount,
- 'devNo': self.device['devNo'],
- 'devTypeCode': self.device.devTypeCode,
- 'devTypeName': self.device.devTypeName,
- 'logicalCode': self.device['logicalCode'],
- 'groupId': self.device['groupId'],
- 'address': address,
- 'groupNumber': group_number,
- 'groupName': group['groupName'],
- 'result': 'success',
- 'remarks': u'刷卡消费',
- 'dateTimeAdded': datetime.datetime.now(),
- 'desc': "",
- 'servicedInfo': servicedInfo
- }
- CardConsumeRecord.get_collection().insert_one(new_card_record)
- return orderNo, cardOrderNo
- @staticmethod
- def update_card_consume_record(orderNo, spendMoney, desc, servicedInfo):
- consumeRcd = ConsumeRecord.objects(orderNo=orderNo).first()
- if not consumeRcd:
- logger.info('can not find the record')
- return None, None
- consumeRcd.coin = VirtualCoin(spendMoney)
- consumeRcd.money = RMB(spendMoney)
- consumeRcd.desc = desc
- consumeRcd.servicedInfo = servicedInfo
- consumeRcd.save()
- cardConsumeRcd = CardConsumeRecord.objects.get(orderNo = consumeRcd.orderNo)
- cardConsumeRcd.money = RMB(spendMoney)
- cardConsumeRcd.desc = desc
- cardConsumeRcd.servicedInfo = servicedInfo
- cardConsumeRcd.save()
- return consumeRcd, cardConsumeRcd
|