123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- # coding=utf-8
- import datetime
- import logging
- import time
- from apilib.monetary import VirtualCoin, RMB
- from apilib.utils_string import make_title_from_dict
- from apps.web.constant import DEALER_CONSUMPTION_AGG_KIND, DeviceCmdCode
- from apps.web.core.accounting import Accounting
- from apps.web.device.models import Device, Group
- from apps.web.eventer import EventBuilder
- from apps.web.eventer.base import WorkEvent, FaultEvent
- from apps.web.user.transaction_deprecated import refund_money
- from apps.web.user.models import ServiceProgress, Card, MyUser, CardRechargeOrder, ConsumeRecord, MonthlyPackage
- logger = logging.getLogger(__name__)
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- event_data = self.deviceAdapter.analyze_event_data(device_event['data'])
- if not event_data:
- return
- event_data['raw_msg'] = device_event
- cmdCode = event_data.get("cmdCode")
- if cmdCode in []:
- return ChaoChenFaultEventer(self.deviceAdapter, event_data)
- return ChaoChenWorkEventer(self.deviceAdapter, event_data)
- class ChaoChenFaultEventer(FaultEvent):
- pass
- class ChaoChenWorkEventer(WorkEvent):
- FINISH_REASON = {
- 0x00: u"充电服务已经结束",
- 0x01: u"用户手动停止",
- 0x02: u"电量充满,充点服务已经结束",
- 0x03: u"当前充电端口出现故障,充电服务结束",
- 0x04: u"功率超出最大限制",
- 0x05: u"当前刷卡结束充电",
- 0x06: u"未连接充电器,充电服务已经结束",
- 0x07: u"远程停止端口,充电服务已经结束",
- 0x08: u"烟雾报警,充电服务已经结束",
- }
- def do(self):
- cmdCode = self.event_data.get("cmdCode")
- logger.info("receive message for dev <{}>, message is <{}>".format(self.device.devNo, self.event_data))
- if cmdCode == "B6":
- self._do_offline_card_finish()
- elif cmdCode == "B5":
- self._do_offline_coin_finish()
- elif cmdCode == "B4":
- pass
- elif cmdCode == "C9":
- self._do_netpay_finish()
-
- elif cmdCode == "C8":
- self._do_online_card_finish()
-
- elif cmdCode == "C4":
- self._do_status_report()
- elif cmdCode == "EA":
- self._do_elec_finish()
-
- elif cmdCode == "F0":
- self._do_elec_report()
-
- elif cmdCode == "F9":
- self._do_consume_id_card()
-
- elif cmdCode == "FA":
- self._do_refund_id_card()
- def _do_offline_card_finish(self):
- portStr = self.event_data['portStr']
- cardNo = self.event_data['cardNo']
- usedCoins = self.event_data['usedCoins']
- usedTime = self.event_data['usedTime']
- balance = self.event_data['balance']
- card = self.update_card_dealer_and_type(cardNo=cardNo, cardType="IC")
- if not card:
- return
- attachParas = {
- "chargeIndex": portStr
- }
- servicedInfo = {
- DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: float(str(usedCoins)),
- DEALER_CONSUMPTION_AGG_KIND.DURATION: float(str(usedTime))
- }
- self.record_consume_for_card(card, VirtualCoin(usedCoins), servicedInfo=servicedInfo, attachParas=attachParas)
- Card.update_balance(cardId=card.id, balance=RMB(balance))
- def _do_offline_coin_finish(self):
- coins = self.event_data['usedCoins']
- self.record_consume_for_coin(VirtualCoin(coins))
- Accounting.recordOfflineCoin(
- self.device,
- int(time.time()),
- int(float(coins))
- )
- def _do_netpay_finish(self):
- portStr = self.event_data['portStr']
- usedTime = self.event_data['usedTime']
- leftTime = self.event_data['leftTime']
- devCache = Device.get_dev_control_cache(self.device.devNo) or dict()
- portCache = devCache.get(portStr) or dict()
- if not portCache:
- return
- openId = portCache.get("openId")
- consumeDict = {
- "duration": usedTime,
- "finishedTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- }
- if self.device.is_auto_refund:
- coins = VirtualCoin(portCache.get("coins", 0))
- usedCoins = min(coins * (float(usedTime) / (float(usedTime) + float(leftTime))), coins)
- refundCoins = coins - usedCoins
- refund_money(self.device, refundCoins, openId)
- consumeDict.update(
- {
- DEALER_CONSUMPTION_AGG_KIND.COIN: float(str(coins)),
- DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: float(str(usedCoins)),
- DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: float(str(refundCoins))
- }
- )
- ServiceProgress.update_progress_and_consume_rcd(
- self.device["ownerId"],
- {
- "open_id": openId,
- "device_imei": self.device.devNo,
- "port": int(portStr),
- "isFinished": False
- },
- consumeDict
- )
- Device.clear_port_control_cache(self.device.devNo, portStr)
- def _do_online_card_finish(self):
- pass
- def _do_status_report(self):
- pass
- def _do_elec_finish(self):
- """
- AA0100EA 03 02 0060 20
- 暂时理解为 只有电量会上报
- :return:
- """
- chargeMode = self.device.get("otherConf", dict()).get("chargeType", self.deviceAdapter.DEFAULT_CHARGE_TYPE)
- # 时间模式直接忽略
- if chargeMode == self.deviceAdapter.DEFAULT_CHARGE_TYPE:
- return
- reasonCode = self.event_data.get("reasonCode", "")
- leftElec = self.event_data.get("leftElec", 0)
- portStr = self.event_data.get("portStr")
- reason = self.FINISH_REASON.get(reasonCode)
- devCache = Device.get_dev_control_cache(self.device.devNo)
- portCache = devCache.get(portStr, dict())
- if not portCache:
- return
- openId = portCache.get("openId")
- needElec = portCache.get("needElec")
- if not openId or not needElec:
- Device.clear_port_control_cache(self.device.devNo, portStr)
- return
- consumeDict = {
- "needElec": needElec,
- "usedElec": needElec - leftElec,
- "leftElec": leftElec,
- "finishData": self.event_data["raw_msg"]["data"]
- }
- if self.device.is_auto_refund:
- coins = VirtualCoin(portCache.get("coins", 0))
- refundCoins = VirtualCoin(coins) * (float(leftElec)/float(needElec))
- refundCoins = min(refundCoins, coins)
- usedCoins = coins - refundCoins
- refund_money(self.device, refundCoins, openId)
- consumeDict.update(
- {
- DEALER_CONSUMPTION_AGG_KIND.COIN: float(str(coins)),
- DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: float(str(usedCoins)),
- DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: float(str(refundCoins))
- }
- )
- ServiceProgress.update_progress_and_consume_rcd(
- self.device["ownerId"],
- {
- "open_id": openId,
- "device_imei": self.device.devNo,
- "port": int(portStr),
- "isFinished": False
- },
- consumeDict
- )
- Device.clear_port_control_cache(self.device.devNo, portStr)
- group = Group.get_group(self.device.get("groupId"))
- user = MyUser.objects.filter(openId=openId, groupId=self.device.get("groupId")).first()
- 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}".format(
- reason=reason,
- logicalCode=self.device["logicalCode"],
- port=portStr,
- group=group["address"],
- ),
- service=u"充电桩充电服务",
- finishTime=datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
- remark=u'谢谢您的支持'
- )
- def _do_elec_report(self):
- totalElec = self.event_data['totalElec']
- otherConf = self.device.get("otherConf", dict())
- otherConf.update({"totalElec": totalElec})
- Device.objects.filter(devNo=self.device.devNo).update(otherConf=otherConf)
- Device.invalid_device_cache(self.device.devNo)
- def _do_consume_id_card(self):
- cardNo = self.event_data.get('cardNo', None)
- port = self.event_data.get('port', None)
- card = self.update_card_dealer_and_type(str(cardNo))
- consumeMoney = RMB(self.event_data.get('consumeMoney'))
-
- if not card or not card.openId or card.frozen:
- logger.info('no find card devNo=<{}> cardNo=<{}>'.format(self.device.devNo, cardNo))
- resp = {
- 'funCode': '{:02X}F9'.format(int(port)),
- 'content': '00',
- }
-
- else:
- # 获取有余额的月票
- monthly_ticket = MonthlyPackage.get_user_ticket(openId=card.openId, groupId=self.device.groupId, cardNo=card.cardNo)
- if len(monthly_ticket):
-
- package = {'coins': 1, 'unit': u'次', 'time': 1}
- ticket = MonthlyPackage.get_can_use_one(monthly_ticket, package)
- if ticket:
- resp = {
- 'funCode': '{:02X}F9'.format(int(port)),
- 'content': '01{:0>8X}{:0>6X}'.format(cardNo, 0),
- }
-
- attachParas = {
- 'chargeIndex': port
- }
-
- servicedInfo = {
- 'cardNo': cardNo,
- 'chargeIndex': port,
- 'monthpackage': str(ticket.id),
- }
-
- orderNo, cardOrderNo = self.record_consume_for_card(card, servicedInfo=servicedInfo,
- attachParas=attachParas, money=RMB(0.0),
- desc=u'包月套餐')
- order = ConsumeRecord.objects.get(orderNo=orderNo)
-
- ticket.deduct(order)
-
- else:
- resp = {
- 'funCode': '{:02X}F9'.format(int(port)),
- 'content': '00',
- }
-
-
- else:
-
- # 检查刷卡的是否有充值订单详情
- 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 >= consumeMoney:
- resp = {
- 'funCode': '{:02X}F9'.format(int(port)),
- 'content': '01{:0>8X}{:0>6X}'.format(cardNo, RMB.yuan_to_fen(card.balance - consumeMoney)),
- }
-
- attachParas = {
- 'chargeIndex': port
- }
-
- servicedInfo = {
- 'cardNo': cardNo,
- 'chargeIndex': port
- }
-
- self.consume_money_for_card(card, consumeMoney)
- orderNo, cardOrderNo = self.record_consume_for_card(card, consumeMoney, servicedInfo=servicedInfo, attachParas=attachParas)
-
- else:
- resp = {
- 'funCode': '{:02X}F9'.format(int(port)),
- 'content': '00',
- }
-
- self.deviceAdapter._send_data(cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, **resp)
- def _do_refund_id_card(self):
- cardNo = self.event_data.get('cardNo', None)
- port = self.event_data.get('port', None)
- card = self.update_card_dealer_and_type(str(cardNo))
- refundMoney = RMB(self.event_data.get('refundMoney'))
-
- if not card or not card.openId or card.frozen:
- logger.info('no find card devNo=<{}> cardNo=<{}>'.format(self.device.devNo, cardNo))
- resp = {
- 'funCode': '{:02X}FA'.format(int(port)),
- 'content': '00',
- }
-
- else:
- resp = {
- 'funCode': '{:02X}FA'.format(int(port)),
- 'content': '01{:0>8X}'.format(cardNo),
- }
-
- if refundMoney >= RMB(0):
-
- monthly_ticket = MonthlyPackage.get_user_ticket(openId=card.openId, groupId=self.device.groupId,
- cardNo=card.cardNo)
- if len(monthly_ticket):
- pass
- else:
- self.refund_money_for_card(refundMoney, str(card.id))
- refundDict = {
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
-
- titleDictList = [
- {u'设备编号': self.device['logicalCode']},
- ]
-
- refundDict.update(
- {
- 'title': make_title_from_dict(titleDictList),
- 'backCount': u'金币:%s' % refundMoney
- }
- )
-
- self.notify_user(card.managerialOpenId, 'refund_coins', **refundDict)
-
- self.deviceAdapter._send_data(cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, **resp)
|