123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import logging
- from apilib.monetary import RMB, VirtualCoin
- from apilib.utils_datetime import to_datetime
- from apps.web.constant import Const, DeviceCmdCode, DEALER_CONSUMPTION_AGG_KIND
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.networking import MessageSender
- from apps.web.device.models import Group, Device
- from apps.web.eventer import EventBuilder
- from apps.web.eventer.base import WorkEvent
- from apps.web.user.models import ServiceProgress, Card, CardRechargeOrder, MyUser
- logger = logging.getLogger(__name__)
- card_is_normal = 1
- card_not_in_db = 2
- card_is_forzen = 3
- card_has_not_order = 4 # IC卡适用
- card_less_balance = 5 # ID卡适用
- card_type_is_ic = 6 # IC卡不允许当做ID卡使用
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
- if event_data is None:
- return None
- if event_data['fun_code'] in [0x35, 0x2C]:
- return ChargingWorkEvent(self.deviceAdapter, event_data)
- class ChargingWorkEvent(WorkEvent):
- def update_balance_for_IC_card(self, card, balance):
- card.balance = balance
- try:
- card.save()
- except Exception, e:
- pass
- def __translate_reason(self, cause, chrmt):
- if cause == 0:
- if chrmt == 1:
- return u'订购时间已经用完。'
- elif chrmt == 2:
- return u'订购电量已经用完。'
- elif cause == 1:
- return u'用户手工停止了充电'
- elif cause == 2:
- return u'充电满了,自动停止'
- elif cause == 3:
- return u'超功率自停'
- elif cause == 4:
- return u'远程断电'
- elif cause == 5:
- return u'刷卡断电'
- elif cause == 0x0B:
- return u'设备或是端口出现问题,被迫停止'
- return u'充电结束。'
- def response_id_card(self, msgDict):
- data = msgDict
- online_card_cost = RMB(self.device['otherConf'].get('online_card_cost', 10) * 0.1) # 元
- online_card_val = self.device['otherConf'].get('online_card_val', 240)
- online_card_chrmt = self.device['otherConf'].get('online_card_chrmt', 1)
-
- mqtt_data = {
- 'fun_code': 0x35,
- 'port_id': data['port_id'],
- 'card_no': data['card_no'],
- 'chrmt': online_card_chrmt,
- 'result': card_not_in_db,
- 'balance': 0,
- 'amount': 0,
- }
-
- cardNo = '{}'.format(int(data['card_no'], 16))
- Card.record_dev_card_no(self.device['devNo'], cardNo)
- card = self.update_card_dealer_and_type(cardNo)
- # 如果没有卡,直接返回
- # cardNo,portId,balance,result
- if card is None:
- return self.send_mqtt(mqtt_data)
-
- if card.frozen:
- data.update(
- {'result': card_is_forzen}
- )
-
- return self.send_mqtt(mqtt_data)
-
- if card.cardType == 'IC': # 如果以前是离线卡,只能用于离线卡,需要提醒用户
- data.update(
- {'result': card_type_is_ic}
- )
-
- return self.send_mqtt(mqtt_data)
-
- #: 首先检查订单,并进行充值
- #: 用户首先在手机客户端充值,需要这个时刻刷卡上报事件将充值的订单同步上来
- card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
- if card_recharge_order:
- result = self.recharge_id_card(card=card,
- rechargeType='append',
- order=card_recharge_order)
- card.reload()
-
- if card.balance >= online_card_cost:
-
- lineInfo = Device.get_dev_control_cache(self.device.devNo).get(str(data['port_id']), {})
- if lineInfo.get('status') == Const.DEV_WORK_STATUS_WORKING:
- return
- consumeDict = {
- 'chargeIndex': data['port_id']
- }
- if online_card_chrmt == 1:
- consumeDict.update({'needTime': online_card_val})
- elif online_card_chrmt == 2:
- consumeDict.update({'needElec': online_card_val})
- online_card_val = online_card_val * 100
- mqtt_data = {
- 'fun_code': 0x35,
- 'port_id': data['port_id'],
- 'card_no': data['card_no'],
- 'chrmt': online_card_chrmt,
- 'balance': int(card.balance - online_card_cost) * 10,
- 'result': card_is_normal,
- 'amount': int(online_card_val),
- }
- result = self.send_mqtt(mqtt_data)
- if result['rst'] == 0:
- self.consume_money_for_card(card, online_card_cost)
- orderNo, cardOrderNo = self.record_consume_for_card(card, online_card_cost, servicedInfo=consumeDict)
-
- lineInfo = {
- "isStart": True,
- "status": Const.DEV_WORK_STATUS_WORKING,
- "openId": card.openId,
- "cardNo": card.cardNo,
- "coins": round(online_card_cost, 2),
- "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- "consumeType": "card",
- "port": data['port_id'],
- "orderNo": orderNo,
- "cardOrderNo": cardOrderNo
- }
-
- Device.update_port_control_cache(self.device.devNo, lineInfo)
-
- ServiceProgress.register_card_service(
- self.device,
- data['port_id'],
- card,
- consumeOrder={
- "orderNo": orderNo,
- "cardOrderNo": cardOrderNo,
- }
- )
- else:
- data.update(
- {
- 'balance': int(card.balance),
- 'result': card_less_balance,
- 'amount': int(online_card_cost),
- }
- )
- return self.send_mqtt(data)
- def do(self, **args):
- funCode = self.event_data['fun_code']
- if funCode == 0x35:
- self.response_id_card(self.event_data)
-
- if funCode == 0x2C:
- self._do_finish()
-
-
-
- def send_mqtt(self, data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, timeout=10):
- """
- 发送mqtt 指令默认210 返回data
- """
- payload = {'IMEI': self.device.devNo, 'data': data}
- result = MessageSender.send(self.device, cmd,
- payload=payload, timeout=timeout)
- if not result.has_key('rst'):
- raise ServiceException({'result': 2, 'description': u'报文异常'})
- if result['rst'] == -1:
- raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- if result['rst'] == 1:
- raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'})
- if result['rst'] == 2:
- raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'})
- else:
- return result
- def _do_finish(self):
- start_type = self.event_data.get('start_type')
- try:
- if start_type == 0: # 离线卡
- self._offline_card_finish()
- elif start_type == 1: # 在线卡
- cardHex = self.event_data.get('card_no')
- cardNo = '{}'.format(int(cardHex, 16))
- Card.record_dev_card_no(self.device['devNo'], cardNo)
- card = self.update_card_dealer_and_type(cardNo)
- # 如果没有卡,直接返回
- # cardNo,portId,balance,result
- if card is None:
- return
- self._online_card_finish(card)
- elif start_type == 2: # 扫码
- self._net_pay_finish()
- except:
- import traceback
- logger.info(traceback.format_exc())
- Device.clear_port_control_cache(self.device.devNo, str(self.event_data['port_id']))
-
- def _offline_card_finish(self):
- print(self.event_data)
- pass
- def _online_card_finish(self,card):
- leftTime = self.event_data.get('left_time')
- leftElec = round(self.event_data.get('left_elec', 0) * 0.001, 3)
- reason = self.event_data.get('reason')
- port = self.event_data.get('port_id')
- lineInfo = Device.get_dev_control_cache(self.device.devNo).get(str(port), {})
- if 'coins' not in lineInfo:
- logger.debug('port cache has no coins. no order in port {}'.format(lineInfo.get('port')))
- return
- orderNo = lineInfo.get('orderNo')
- coins = VirtualCoin(lineInfo.get('coins'))
- openId = lineInfo.get('openId')
- chrmt = self.event_data.get('chrmt') or lineInfo.get('chmrt')
- startTime = to_datetime(lineInfo['startTime'])
- nowTime = datetime.datetime.now()
- if startTime > nowTime: # 如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
- usedTime = 0
- else:
- usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0)))
- extra = []
- consumeDict = {
- 'port': port,
- 'reason': self.__translate_reason(reason, chrmt),
- DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount,
- }
- refundProtectionTime = lineInfo.get('refundProtectionTime', 5)
- backCoins = VirtualCoin(0)
- usedFee = coins
- if usedTime < refundProtectionTime:
- backCoins = coins
- usedFee = VirtualCoin(0)
- else:
- if self.device.is_auto_refund:
- if chrmt == 1:
- needTime = lineInfo.get('needTime')
- if leftTime == 0xFFFF:
- actualNeedTime = 0
- backCoins = coins
- usedFee = VirtualCoin(0)
- else:
- actualNeedTime = usedTime + leftTime
- backCoins = self.get_backCoins(coins, leftTime, actualNeedTime)
- usedFee = coins - backCoins
- consumeDict.update({
- 'needTime': needTime,
- 'actualNeedTime': actualNeedTime,
- 'leftTime': leftTime,
- })
- elif chrmt == 2:
- needElec = round(lineInfo.get('needElec', 0) * 0.001, 3)
- if leftElec > needElec:
- leftElec = needElec
- elec = 0
- backCoins = coins
- usedFee = VirtualCoin(0)
- else:
- elec = round((needElec - leftElec) * 0.001, 3)
- backCoins = self.get_backCoins(coins, leftElec, needElec)
- usedFee = coins - backCoins
- consumeDict.update({
- 'needElec': needElec,
- 'elec': elec,
- 'leftElec': leftElec,
- })
- else:
- pass
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {
- 'open_id': openId, 'device_imei': self.device['devNo'],
- 'port': port, 'isFinished': False
- },
- consumeDict)
- user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first()
- group = Group.get_group(self.device['groupId'])
- # 处理退费 与推送
- if backCoins > VirtualCoin(0):
- extra.append({u'消费明细': u'消费{}金币,退费{}金币'.format(usedFee, backCoins)})
- self.refund_money_for_card(backCoins, str(card.id), orderNo)
- else:
- extra.append({u'消费明细': u'消费{}(金币)'.format(usedFee)})
- self.notify_user_service_complete(
- service_name='充电',
- openid=card.managerialOpenId,
- port=str(port),
- address=group.address,
- reason=self.event_data.get('reasonDesc'),
- finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra)
- def _net_pay_finish(self):
- leftTime = self.event_data.get('left_time')
- leftElec = round(self.event_data.get('left_elec', 0) * 0.001, 3)
- reason = self.event_data.get('reason')
- port = self.event_data.get('port_id')
-
- lineInfo = Device.get_dev_control_cache(self.device.devNo).get(str(port), {})
- if 'coins' not in lineInfo:
- logger.debug('port cache has no coins. no order in port {}'.format(lineInfo.get('port')))
- Device.clear_port_control_cache(self.device.devNo, (port))
- return
-
- coins = VirtualCoin(lineInfo.get('coins'))
- openId = lineInfo.get('openId')
- chrmt = self.event_data.get('chrmt') or lineInfo.get('chmrt')
- startTime = to_datetime(lineInfo['startTime'])
- nowTime = datetime.datetime.now()
- if startTime > nowTime: # 如果web服务器时间和事件监控服务器时间不一致,导致开始时间比事件时间还大
- usedTime = 0
- else:
- usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0)))
- extra = []
- consumeDict = {
- 'port': port,
- 'reason': self.__translate_reason(reason, chrmt),
- DEALER_CONSUMPTION_AGG_KIND.COIN: coins.mongo_amount,
- }
-
- refundProtectionTime = self.device['otherConf'].get('refundProtectionTime', 5)
-
- backCoins = VirtualCoin(0)
- usedFee = coins
-
- if usedTime < refundProtectionTime:
- backCoins = coins
- usedFee = VirtualCoin(0)
- else:
- if self.device.is_auto_refund:
- if chrmt == 1:
- needTime = lineInfo.get('needTime')
- if leftTime == 0xFFFF:
- actualNeedTime = 0
- backCoins = coins
- usedFee = VirtualCoin(0)
- else:
- actualNeedTime = usedTime + leftTime
- backCoins = self.get_backCoins(coins, leftTime, actualNeedTime)
- usedFee = coins - backCoins
-
- consumeDict.update({
- 'needTime': needTime,
- 'actualNeedTime': actualNeedTime,
- 'leftTime': leftTime,
- })
-
- elif chrmt == 2:
- needElec = round(lineInfo.get('needElec', 0) * 0.001, 3)
- if leftElec > needElec:
- leftElec = needElec
- elec = 0
- backCoins = coins
- usedFee = VirtualCoin(0)
- else:
- elec = round((needElec - leftElec) * 0.001, 3)
- backCoins = self.get_backCoins(coins, leftElec, needElec)
- usedFee = coins - backCoins
-
- consumeDict.update({
- 'needElec': needElec,
- 'elec': elec,
- 'leftElec': leftElec,
- })
- else:
- pass
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {
- 'open_id': openId, 'device_imei': self.device['devNo'],
- 'port': port, 'isFinished': False
- },
- consumeDict)
-
- user = MyUser.objects(openId=openId, groupId=self.device['groupId']).first()
- group = Group.get_group(self.device['groupId'])
- # 处理退费 与推送
- if backCoins > VirtualCoin(0):
- extra.append({u'消费明细': u'消费{}金币,退费{}金币'.format(usedFee, backCoins)})
- self.refund_net_pay(user, lineInfo, RMB(0), backCoins, consumeDict, False)
- else:
- extra.append({u'消费明细': u'消费{}(金币)'.format(usedFee)})
- self.notify_user_service_complete(
- service_name='充电',
- openid=user.managerialOpenId,
- port=str(port),
- address=group.address,
- reason=self.event_data.get('reasonDesc'),
- finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
|