123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import logging
- import random
- import time
- import simplejson as json
- from bson import ObjectId
- from mongoengine import DoesNotExist, ValidationError
- from typing import TYPE_CHECKING
- from apilib.monetary import RMB, VirtualCoin, Ratio
- from apilib.utils_datetime import to_datetime
- from apilib.utils_sys import memcache_lock
- from apps import serviceCache
- from apps.web.agent.models import Agent
- from apps.web.common.models import TempValues
- from apps.web.constant import FAULT_CODE, FAULT_LEVEL, Const, DEALER_CONSUMPTION_AGG_KIND, USER_RECHARGE_TYPE
- from apps.web.core.accounting import Accounting
- from apps.web.core.payment import WithdrawGateway
- from apps.web.dealer.models import Dealer
- from apps.web.device.models import Group, Device
- from apps.web.eventer import EventBuilder
- from apps.web.eventer.base import WorkEvent, FaultEvent
- from apps.web.report.ledger import Ledger
- from apps.web.user.models import CardRechargeOrder, Card, RechargeRecord, CardRechargeRecord, ServiceProgress, \
- ConsumeRecord, CardConsumeRecord, MyUser, UserVirtualCard
- if TYPE_CHECKING:
- from apps.web.device.models import GroupDict
- logger = logging.getLogger(__name__)
- class PayTypeEnum(object):
- COUNT_CARD = '00'
- NET_PAY = '01'
- OFFLINE_COIN = '02'
- PREPAID_CARD = '03'
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- eventData = self.deviceAdapter.analyze_event_data(device_event.get('data'))
- if eventData is None or 'cmdCode' not in eventData:
- return None
- if "ack_id" in device_event:
- eventData["ack_id"] = device_event["ack_id"]
- if eventData['cmdCode'] == 'D7':
- return ChangYuanFaultEventer(self.deviceAdapter, eventData)
- else:
- return ChangYuanWorkEventer(self.deviceAdapter, eventData)
- class ChangYuanFaultEventer(FaultEvent):
- def do(self, **args):
- if "ack_id" in self.event_data:
- self.deviceAdapter._ack(self.event_data["ack_id"])
- self.event_data.update({
- 'faultName': u'设备火灾预警',
- 'faultCode': FAULT_CODE.FIRE_ALARM,
- 'level': FAULT_LEVEL.CRITICAL,
- 'desc': u'主板上报设备火警'
- })
- warningData = {
- "warningStatus": 2,
- "warningDesc": "设备温度超限警告",
- "warningTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
- }
- # 整机告警
- Device.update_dev_warning_cache(self.device.devNo, {"0": warningData})
- super(ChangYuanFaultEventer, self).do(**args)
- class ChangYuanWorkEventer(WorkEvent):
- def do(self, **args):
- if "ack_id" in self.event_data:
- self.deviceAdapter._ack(self.event_data['ack_id'])
- cmdCode = self.event_data.get('cmdCode')
- cacheKey = '{}-{}-event'.format(self.device.devNo, cmdCode)
- with memcache_lock(key=cacheKey, value='1', expire=120) as acquired:
- if acquired:
- if cmdCode == 'D3':
- self._do_recharge_card_result()
- elif cmdCode == 'D4':
- self._do_recharge_card()
- elif cmdCode == 'D9':
- self._do_start_charge()
- elif cmdCode == 'DA':
- self._do_finish()
- elif cmdCode == 'DE':
- self._do_card_refund()
- else:
- logger.warning(
- 'cyp_event is doing!, dev is <{}>, cacheKey is <{}>, cmd is <{}>, data is <{}>'.format(
- self.device.devNo,
- cacheKey,
- cmdCode,
- self.event_data
- )
- )
- def _do_card_refund(self):
- beforeRefund = self.event_data.get('beforeRefund')
- refund = self.event_data.get('refund')
- afterRefund = self.event_data.get('afterRefund')
- cardNo = str(self.event_data.get('cardNo'))
- # 指令上传错误
- if VirtualCoin(beforeRefund) + VirtualCoin(refund) != VirtualCoin(afterRefund):
- logger.info('bad refund event, beforeRefund is {}, refund is {} afterRefund is {}'.format(
- beforeRefund, refund, afterRefund
- ))
- return
- # 查找卡的消息 一定要是预付费卡
- card = self._update_card_dealer_and_type(cardNo, "01")
- if not card:
- return
- # 查看返费前的金额是否是相等的
- if VirtualCoin(card.balance) != VirtualCoin(beforeRefund):
- logger.info(
- 'beforeRefund is not equal card balance, cardNo is {}, beforeRefund is {}, card balance is {}'.format(
- cardNo, beforeRefund, card.balance
- ))
- return
- # 退费
- self.refund_money_for_card(RMB(refund), str(card.id))
- # 通知用户
- self.notify_user(
- card.managerialOpenId or "",
- 'refund_coins',
- **{
- 'title': u'预付卡充电桩返费',
- 'backCount': u'%s' % refund,
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
- )
- @staticmethod
- def _do_update_ConsumeRecord_CardConsumeRecord_service_progress(portCache, updateMoney):
- portCache['payCount'] = portCache.get('payCount') + 1
- portCache['allPayMoney'] = updateMoney
- portCache['coins'] = updateMoney
- orderNo = portCache.get('orderNo')
- cardOrderNo = portCache.get('cardOrderNo')
- try:
- order = ConsumeRecord.objects.get(orderNo=orderNo)
- card_order = CardConsumeRecord.objects.get(orderNo=cardOrderNo)
- service_pogress = ServiceProgress.objects(__raw__={'consumeOrder.orderNo': orderNo}).first()
- order.coin = updateMoney
- order.money = updateMoney
- card_order.money = updateMoney
- service_pogress.consumeOrder['money'] = updateMoney
- service_pogress.consumeOrder['coin'] = updateMoney
- order.save()
- card_order.save()
- service_pogress.save()
- except Exception as e:
- logger.debug('%s' % e)
- finally:
- pass
- def _do_recharge_card(self):
- """
- 同步卡的请求
- :return:
- """
- cardNo = self.event_data.get('cardNo')
- cardBalance = self.event_data.get('cardBalance')
- cardType = self.event_data.get('cardType')
- # 查询卡 包括卡的类型
- card = self._update_card_dealer_and_type(cardNo, billing_method=cardType)
- if not card:
- return
- # 更新卡的余额 以设备侧的为准
- if RMB(cardBalance) != card.balance:
- logger.info('Card<{}> balance<{}> needs to be sync !!!'.format(cardNo, card.balance))
- card.balance = RMB(cardBalance)
- card = card.save()
- # orderNos 表示充值的订单 cardOrderNos 表示卡充值的订单
- money, coins, orderNos, cardOrderNos = CardRechargeOrder.get_to_do_list(str(card.id))
- # 一旦卡被冻结 立即下发 创建一张为 负数的金额订单 将卡的余额清空
- if card.frozen:
- group = Group.get_group(card.groupId)
- CardRechargeOrder.new_one(
- openId=card.openId,
- cardId=str(card.id),
- cardNo=card.cardNo,
- money=RMB(0),
- coins=VirtualCoin(0) - VirtualCoin(coins) - VirtualCoin(card.balance),
- group=group,
- rechargeId=ObjectId(),
- rechargeType='sendCoin'
- )
- money, coins, orderNos, cardOrderNos = CardRechargeOrder.get_to_do_list(str(card.id))
- # 没有需要同步的订单的情况下 直接退出
- if not orderNos:
- logger.info('Not card recharge record!, card is <{}>'.format(cardNo))
- # self._do_offline_recharge_by_dealer(cardNo, card, cardType)
- return
- orderNos = [str(item) for item in orderNos]
- sid = str(random.randint(0, 0xFFFF))
- TempValues.set('%s-%s' % (self.device.devNo, sid), value=json.dumps(orderNos))
- TempValues.set('%s-%s-%s' % (self.device.devNo, sid, cardNo), value=json.dumps(cardOrderNos))
- TempValues.set('%s-%s' % (self.device.devNo, cardNo), value=str(sid))
- # 计算总的需要同步的金额
- asyncMoney = RMB(cardBalance) + RMB(coins)
- logger.info('ready to recharge card, card is <{}>, money is <{}>'.format(cardNo, coins))
- # 已经下发金额后,先将订单的状态改为结束。如果主板上报失败,再将订单状态迁移回来否则就不再变化订单状态了
- try:
- CardRechargeOrder.update_card_order_has_finished(str(card.id))
- except Exception as e:
- logger.debug('%s' % e)
- else:
- self.deviceAdapter._async_card_balance(cardType, cardNo, asyncMoney)
- def _do_recharge_card_result(self):
- """
- 确认卡的同步结果
- :return:
- """
- asyncStatus = self.event_data.get('result')
- answerSid = self.event_data.get('sid')
- cardBalance = self.event_data.get('cardBalance')
- cardNo = str(self.event_data.get('cardNo'))
- cardType = self.event_data.get('cardType')
- # 先找卡 卡都不存在的话 直接推掉
- card = self._update_card_dealer_and_type(cardNo, cardType)
- if not card:
- return
- sid = TempValues.get('{}-{}'.format(self.device.devNo, cardNo))
- if sid != answerSid:
- logger.error('answer sid is not equal sid <{}>-<{}>'.format(sid, answerSid))
- return
- # 根据sid 以及卡号 查询出此次充值的所有的订单
- orderNos = TempValues.get('{}-{}'.format(self.device.devNo, sid))
- cardOrderNos = TempValues.get('{}-{}-{}'.format(self.device.devNo, sid, cardNo))
- # 明确接收到了主板同步失败的情况下 直接退出 不在转换充值订单的问题 防止出错
- if not asyncStatus:
- logger.error("card async not success! event data is <{}>".format(self.event_data))
- return
- # 下面的都不会更改订单的状态 最多走售后
- money, coins = RMB(0), VirtualCoin(0)
- # 校验金额是否是相等的
- orderNos = [ObjectId(item) for item in orderNos]
- rds = RechargeRecord.objects.filter(ownerId=card.dealerId, id__in=orderNos)
- for item in rds:
- money += item.money
- coins += item.coins
- # 这个地方就是异常值处理了
- if VirtualCoin(coins + card.balance) != VirtualCoin(cardBalance):
- logger.error('card pre balance not equal now balance! event is <{}>'.format(self.event_data))
- return
- # 依次更改卡充值的订单 并创建充值订单
- cardOrders = CardRechargeOrder.objects.filter(orderNo__in=cardOrderNos)
- for _order in cardOrders: # type: CardRechargeOrder
- _order.update_after_recharge_ic_card(
- device=self.device,
- sendMoney=RMB(_order.coins),
- preBalance=card.balance
- )
- preBalance = card.balance
- card.balance = card.balance + _order.coins
- # 创建充值记录
- CardRechargeRecord.add_record(
- card=card,
- group=Group.get_group(_order.groupId),
- order=_order,
- device=self.device
- )
- # 保存
- card.save()
- # 完成之后将TempValue 的key value 清空
- TempValues.remove('%s-%s' % (self.device['devNo'], sid))
- TempValues.remove('%s-%s' % (self.device['devNo'], cardNo))
- TempValues.remove("%s-%s-%s" % (self.device["devNo"], sid, cardNo))
- def _do_start_charge(self):
- '''
- 充电开始指令, 主要是更新各种缓存等等,
- 对于扫码的启动基本在adapter缓存已经处理完成,主要需要处理的是刷卡的启动
- 根据 需求方要求 刷卡的可以做合单处理
- :return:
- '''
- logger.info(
- 'do_start_charge() is run!! event_data:{}'.format(self.event_data))
- portStr = str(self.event_data.get('port'))
- ctrInfo = Device.get_dev_control_cache(self.device.devNo)
- lineInfo = ctrInfo.get(portStr, {'port': portStr})
- payType = self.event_data.get('payType')
- if payType == PayTypeEnum.NET_PAY: # 线上支付
- if lineInfo.get('status', Const.DEV_WORK_STATUS_IDLE) == Const.DEV_WORK_STATUS_IDLE:
- lineInfo['power'] = self.event_data.get('power')
- lineInfo['payType'] = self.event_data.get('payType')
- lineInfo['needTime'] = self.event_data.get('needTime')
- logger.info("NET_PAY is ok!!")
- else:
- lineInfo['power'] = self.event_data.get('power')
- lineInfo['needTime'] = self.event_data.get('needTime')
- logger.info("NET_PAY is ok!!")
- Device.update_port_control_cache(self.device.devNo, lineInfo)
- return
- elif payType == PayTypeEnum.OFFLINE_COIN:
- Accounting.recordOfflineCoin(self.device,
- int(time.time()),
- int(self.event_data['coins']))
- orderNo = self.record_consume_for_coin(RMB(self.event_data["coins"]))
- Device.update_port_control_cache(
- self.device["devNo"],
- {'port': portStr,
- "isStart": True,
- "coins": self.event_data["coins"],
- "needTime": self.event_data["needTime"],
- "power": self.event_data["power"],
- "payType": self.event_data["payType"],
- "startTime": datetime.datetime.now().strftime(Const.DATETIME_FMT),
- "status": Const.DEV_WORK_STATUS_WORKING,
- "consumeOrderNo": orderNo,
- "payInfo": [{
- "coins": float(self.event_data["coins"]),
- "price": float(self.event_data["coins"]),
- "needTIme": self.event_data["needTime"],
- "consumeOrderNo": orderNo
- }]
- })
- else:
- cardNo = self.event_data.get('cardNo')
- if cardNo == '00000000':
- # 可能是虚拟卡 暂不处理
- return
- cardBalance = RMB(self.event_data.get('cardBalance'))
- coins = self.event_data.get('coins')
- card = self._update_card_dealer_and_type(cardNo, billing_method=self.event_data["cardType"])
- needTime = self.event_data.get('needTime')
- needBindCard = self.device['otherConf'].get('needBindCard', True)
- if not card:
- if needBindCard: # 需要绑卡却没有绑卡 直接停止
- return self.deviceAdapter.stop_charging_port(portStr)
- else:
- return
- if card.frozen:
- self.notify_invalid_card_to_dealer(cardNo, card)
- # 停止此离线卡的充电行为
- self.deviceAdapter.stop_charging_port(portStr)
- return
- if not Group.is_currency_mode_group(card.groupId, self.device.groupId): # 地址组通用校验
- logger.info(
- 'is_currency_mode_group is fail <{}> card_group=<{}> dev_group=<{}>'.format(cardNo, card.groupId,
- self.device.groupId))
- return self.deviceAdapter.stop_charging_port(portStr)
- # 离线卡 以设备上报过来的数据为准
- card.balance = cardBalance.mongo_amount
- card.save()
- card.reload()
- if lineInfo.get('status',
- Const.DEV_WORK_STATUS_IDLE) != Const.DEV_WORK_STATUS_IDLE and cardNo == lineInfo.get(
- 'cardNo'):
- logger.info('Card<{}> Swipe to pay again!!'.format(cardNo))
- orderNo = lineInfo.get('orderNo')
- cardOrderNo = lineInfo.get('cardOrderNo')
- lineInfo['coins'] += coins
- lineInfo['payCount'] += 1
- if not needTime:
- needTime = 0
- # lineInfo['needTime'] = needTime
- ConsumeRecord.objects.filter(orderNo=orderNo).update_one(inc__coin=coins, inc__money=coins)
- CardConsumeRecord.objects.filter(orderNo=cardOrderNo).update_one(inc__money=coins, dec__balance=coins)
- ServiceProgress.objects.filter(device_imei=self.device.devNo, port=int(portStr),
- consumeOrder__orderNo=orderNo, isFinished=False).update_one(
- inc__consumeOrder__coin=coins, inc__finished_time=(time.time() + needTime * 60))
- # 第一次刷卡
- else:
- logger.info('Card<{}> start charge the once!!'.format(cardNo))
- # 记录ID卡的消费
- attachParas = {
- 'chargeIndex': portStr
- }
- servicedInfo = {
- 'cardNo': cardNo,
- 'chargeIndex': portStr
- }
- orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(coins), servicedInfo=servicedInfo,
- attachParas=attachParas)
- # 记录缓存信息 可以在个人中心以及经销商的端口管理显示
- lineInfo = {
- 'port': portStr,
- 'cardNo': cardNo,
- 'openId': card.openId,
- 'payCount': 1,
- 'coins': coins,
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- 'orderNo': orderNo,
- 'cardOrderNo': cardOrderNo,
- 'payType': payType,
- 'consumeType': 'card',
- }
- finishedTime = None
- if needTime:
- finishedTime = int(time.time()) + needTime * 60
- # lineInfo['needTime'] = needTime
- ServiceProgress.register_card_service(
- self.device,
- int(portStr),
- card,
- {
- 'orderNo': orderNo,
- 'coin': VirtualCoin(coins).mongo_amount,
- 'cardOrderNo': cardOrderNo
- },
- finishedTime)
- logger.info('port:{} is running, order:{} cardOrder:{}'.format(portStr, orderNo, cardOrderNo))
- # 更新端口缓存
- Device.update_port_control_cache(self.device.devNo, lineInfo)
- # 通知卡消费成功
- self.notify_balance_has_consume_for_card(card, coins)
- def _do_finish(self):
- '''
- 充电结束的指令
- :return:
- '''
- portStr = str(self.event_data.get('port'))
- FINISHED_COUNT_KEY = 'device_port_finish_{}_{}'.format(self.device.devNo, portStr)
- count = serviceCache.get(FINISHED_COUNT_KEY, 0)
- ctrInfo = Device.get_dev_control_cache(self.device.devNo)
- lineInfo = ctrInfo.get(portStr)
- if not lineInfo or lineInfo.get('payType') is None:
- logger.info('cache is missing ,DA is over')
- return
- duration = ((datetime.datetime.now() - to_datetime(lineInfo.get('startTime'))).total_seconds() + 59) // 60
- if duration < 3:
- count += 1
- serviceCache.set(FINISHED_COUNT_KEY, count, 60 * 60 * 24)
- if count >= 3:
- self.notify_fault_to_dealer()
- serviceCache.delete(FINISHED_COUNT_KEY)
- payType = lineInfo.get('payType')
- try:
- if payType == PayTypeEnum.NET_PAY:
- self._do_netpay_finish(portStr, lineInfo)
- elif payType == PayTypeEnum.OFFLINE_COIN:
- self._do_offline_coin_finish(portStr, lineInfo)
- else:
- self._do_card_finish(portStr, lineInfo)
- except Exception as e:
- logger.error('DA is over error:{}'.format(e))
- Device.clear_port_control_cache(self.device.devNo, portStr)
- def _do_card_finish(self, portStr, lineInfo):
- logger.info('do card finished lineInfo={} ||| event_data={}'.format(lineInfo, self.event_data))
- extra = []
- coins = lineInfo.get('coins')
- cardNo = lineInfo.get('cardNo')
- card = self.update_card_dealer_and_type(cardNo, cardType='IC')
- if not card:
- logger.debug('server no find card!!! cardNo=<{}>'.format(cardNo))
- return
- extra.append({u'使用卡片': u'{}--{}'.format(card.cardName, cardNo)})
- consumeDict = {
- 'port': portStr,
- 'cardNo': cardNo,
- 'elec': self.event_data.get('usedElec'),
- 'reason': self.event_data.get('reason'),
- }
- payType = lineInfo.get('payType')
- if payType == PayTypeEnum.COUNT_CARD:
- # leftTime = self.event_data.get('left')
- now = datetime.datetime.now()
- # consumeDict['leftTime'] = leftTime
- consumeDict['duration'] = ((now - to_datetime(lineInfo.get('startTime'))).total_seconds() + 59) // 60
- # consumeDict['actualNeedTime'] = '动态计算时间为{}分钟'.format(consumeDict['duration'] + leftTime)
- # extra.append({u"使用详情": u"本次使用{}分钟,剩余{}分钟".format(consumeDict['duration'], consumeDict['leftTime'])})
- extra.append({u"使用详情": u"本次使用{}分钟".format(consumeDict['duration'])})
- elif payType == PayTypeEnum.PREPAID_CARD:
- leftMoney = self.event_data.get('leftMoney')
- if leftMoney:
- leftMoney = float(leftMoney)
- coins = float(coins)
- if leftMoney > coins:
- leftMoney = coins
- refundedMoney = round(leftMoney, 2)
- consumeDict['spendMoney'] = round(coins - leftMoney, 2)
- extra.append(
- {u"消费明细": u"消费{}金币,剩余{}金币(等待靠卡退费)".format(consumeDict['spendMoney'], refundedMoney)})
- else:
- consumeDict['spendMoney'] = round(coins, 2)
- extra.append(
- {u"消费明细": u"消费{}金币".format(coins)})
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {
- 'device_imei': self.device['devNo'],
- 'cardId': str(card.id),
- 'port': int(portStr),
- 'isFinished': False
- },
- consumeDict
- )
- self.notify_to_user(card.managerialOpenId, extra)
- logger.info('do_card_finish is finished!!')
- def _do_netpay_finish(self, portStr, lineInfo):
- logger.info('netpay_finish is running !! event_data:{}'.format(
- json.dumps(self.event_data, ensure_ascii=False)))
- usedElec = self.event_data.get('spendElec')
- reason = self.event_data.get('reason')
- leftMoney = self.event_data.get('leftMoney')
- extra = []
- openId = lineInfo.get('openId')
- coins = VirtualCoin(lineInfo.get('coins', 0))
- money = RMB(lineInfo.get('price', 0))
- payInfo = lineInfo.get('payInfo')
- vCardId = lineInfo.get('vCardId')
- now = datetime.datetime.now()
- duration = (now - to_datetime(lineInfo.get('startTime'))).total_seconds() // 60
- refundMoney = RMB(leftMoney)
- if duration <= 5:
- refundMoney = money
- # 如果没有openId则为经销商远程上分
- if not openId:
- logger.info('Remote activation by dealer')
- return
- else:
- user = MyUser.objects.filter(openId=openId, groupId=self.device['groupId']).first()
- consumeDict = {
- 'port': portStr,
- 'elec': usedElec,
- 'duration': duration,
- 'reason': reason,
- }
- logger.info('ChangYuanPower net pay finish and start to notify user! {}-{}'.format(self.device['devNo'],
- portStr))
- if duration > 5:
- extra.append({u'充电时长': u'{}分钟'.format(duration)})
- else:
- extra.append({u'充电时长': u'0分钟'})
- if self.device.is_auto_refund or duration <= 5:
- if payInfo:
- # 先做现金分账
- for item in payInfo:
- self.do_ledger(item['rechargeRcdId'])
- # 现金退款
- self.refund_net_pay(user, lineInfo, refundedMoney=refundMoney, refundCoins=VirtualCoin(0),
- consumeDict=consumeDict, is_cash=True)
- extra.append({u'消费明细': u'支付{}元,退款{}元'.format(money, refundMoney)})
- elif vCardId:
- try:
- vCard = UserVirtualCard.objects.get(id=vCardId)
- extra.append({u'虚拟卡券': u'{}--{}'.format(vCard.cardName, vCard.cardNo)})
- except DoesNotExist:
- logger.info('can not find the vCard id = %s' % vCardId)
- pass
- pass
- else:
- self.refund_net_pay(user, lineInfo, refundedMoney=RMB(0), refundCoins=VirtualCoin(refundMoney),
- consumeDict=consumeDict, is_cash=False)
- extra.append({u'消费明细': u'消费{}金币,退款{}金币'.format(coins, VirtualCoin(refundMoney))})
- else:
- extra.append({u'消费明细': u'消费{}金币'.format(coins)})
- if payInfo:
- for item in payInfo:
- self.do_ledger(item['rechargeRcdId'])
- ServiceProgress.update_progress_and_consume_rcd(
- self.device['ownerId'],
- {
- 'open_id': openId,
- 'device_imei': self.device['devNo'],
- 'port': int(portStr),
- 'isFinished': False
- },
- consumeDict
- )
- self.notify_to_user(openId=user.managerialOpenId, extra=extra)
- logger.info('do_netpay_finish() is over !!')
- def _update_card_dealer_and_type(self, cardNo, billing_method):
- """
- 昌原的都是IC卡 并且需要标注卡类型
- :param cardNo: 卡号
- :param billing_method: 卡类型
- :return:
- """
- card = self.update_card_dealer_and_type(cardNo, "IC") # type: Card
- if not card:
- logger.error("not found card <{}>, event is <{}>".format(cardNo, self.event_data))
- return None
- # 没有卡的计费类型的 说明是经销商新添加的卡 添加上计费类型 有了卡计费类型的 需要比较卡计费类型是否正确 如果不正确的 说明卡不正确
- if not card.billing_method:
- card.billing_method = billing_method
- if not card.billing_method_equal(billing_method):
- logger.error("card <{}> billing_method not equal!, event is <{}>".format(cardNo, self.event_data))
- return None
- return card
- def update_card_dealer_and_type(self, cardNo, cardType='ID', isHaveBalance=True, balance=None):
- """
- 更新卡的状态 重写目的 如果卡不存在 立即下发停止充电指令 而不是新建一张卡
- :param cardNo:
- :param cardType:
- :param isHaveBalance:
- :param balance:
- :return:
- """
- dealer = Dealer.objects.get(id=self.device['ownerId'])
- agent = Agent.objects.get(id=dealer.agentId)
- if not agent:
- logger.error('agent is not found, agentId=%s' % dealer.agentId)
- return
- try:
- card = Card.objects.filter(cardNo=cardNo, agentId=dealer.agentId).first()
- if not card:
- return None
- # 如果卡没有被绑定,这个时候检查下绑定关系。如果卡已经被某个经销商认领了,就不要刷新,不要动了
- if card.cardType and card.dealerId and card.devNo and (card.dealerId == self.device['ownerId']):
- return card
- else:
- card.dealerId = self.device['ownerId']
- card.devNo = self.device['devNo']
- card.cardType = cardType
- card.devTypeCode = self.device['devType']['code']
- card.isHaveBalance = isHaveBalance
- card.save()
- return card
- except Exception as e:
- logger.exception(e)
- return
- def notify_to_user(self, openId, extra):
- group = Group.get_group(self.device['groupId'])
- self.notify_user_service_complete(
- service_name='充电',
- openid=openId,
- port=self.event_data['port'],
- address=group['address'],
- reason=self.event_data.get('reason'),
- finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra)
- def notify_invalid_card_to_dealer(self, cardNo, card):
- logger.info('Illegal card <{}>, charging is about to stop'.format(cardNo))
- group = Group.get_group(self.device['groupId'])
- self.notify_dealer(
- 'device_fault',
- title=u'注意!注意!您当前的设备已被非法卡使用!',
- device=u'组号::%s, 二维码编号:%s' % (self.device['groupNumber'], self.device['logicalCode']),
- location=u'组名称:%s, 地址:%s' % (group['groupName'], group['address']),
- fault=u'在%s编号为%s的设备被非法卡卡启动,启动卡号为:%s 卡联系人 %s 卡联系电话 %s' % (
- group['address'], self.device['logicalCode'], card.cardNo if card else '',
- card.phone if card else '', card.cardName if card else ''),
- notifyTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- )
- def _do_offline_coin_finish(self, portStr, lineInfo):
- CoinConsumeRcd = ConsumeRecord.objects.get(orderNo=lineInfo.get('consumeOrderNo'))
- startTime = lineInfo.get('startTime')
- startTime = to_datetime(startTime)
- nowTime = datetime.datetime.now()
- if startTime > nowTime:
- usedTime = 0
- else:
- usedTime = int(round(((nowTime - startTime).total_seconds() / 60.0)))
- consumeDict = {
- 'chargeIndex': portStr,
- 'reason': self.event_data.get('reason'),
- 'leftTime': self.event_data.get('left', 0),
- 'actualNeedTime': usedTime + self.event_data.get('left', 0),
- DEALER_CONSUMPTION_AGG_KIND.DURATION: usedTime,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: self.event_data.get('usedElec'),
- DEALER_CONSUMPTION_AGG_KIND.TOTAL_COUNT: lineInfo.get('coins'),
- }
- CoinConsumeRcd.update_service_info(consumeDict)
- CoinConsumeRcd.update(status='finished', finishedTime=nowTime)
- def notify_fault_to_dealer(self):
- group = self.device.group
- self.notify_dealer(
- templateName='device_fault',
- title=u'端口连续停止超过三次',
- device=u'{groupNumber}组-{logicalCode}-端口{port}'.format(groupNumber=self.device['groupNumber'],
- logicalCode=self.device['logicalCode'],
- port=self.event_data.get('port')),
- location=u'{address}-{groupName}'.format(address=group['address'], groupName=group['groupName']),
- fault=u'端口连续停止超过三次',
- notifyTime=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- )
- def anonymous_user_start(self, lineInfo):
- coins = self.event_data.get('coins')
- cardNo = self.event_data.get('cardNo')
- port = self.event_data.get('port')
- needTime = self.event_data.get('needTime')
- cardBalance = self.event_data.get('cardBalance')
- payType = self.event_data.get('payType')
- if lineInfo.get('status', Const.DEV_WORK_STATUS_IDLE) != Const.DEV_WORK_STATUS_IDLE and cardNo == lineInfo.get(
- 'cardNo'):
- logger.info('anonymous_user card<{}> Swipe to pay again!!'.format(cardNo))
- orderNo = lineInfo.get('orderNo')
- cardOrderNo = lineInfo.get('cardOrderNo')
- lineInfo['coins'] += coins
- lineInfo['payCount'] += 1
- if not needTime:
- needTime = 0
- # lineInfo['needTime'] = needTime
- ConsumeRecord.objects.filter(orderNo=orderNo).update_one(inc__coin=coins, inc__money=coins)
- CardConsumeRecord.objects.filter(orderNo=cardOrderNo).update_one(inc__money=coins, dec__balance=coins)
- ServiceProgress.objects.filter(device_imei=self.device.devNo, port=port,
- consumeOrder__orderNo=orderNo, isFinished=False).update_one(
- inc__consumeOrder__coin=coins, inc__finished_time=(time.time() + needTime * 60))
- # 第一次刷卡
- else:
- logger.info('anonymous_user card<{}> start charge the once!!'.format(cardNo))
- card = Card(
- cardNo=cardNo,
- dealerId=self.device.ownerId,
- agentId=self.device.owner.agentId,
- groupId=self.device.groupId,
- openId=Const.DEFAULT_CARD_OPENID,
- balance=RMB(cardBalance),
- ).save()
- # 记录ID卡的消费
- attachParas = {
- 'chargeIndex': port
- }
- servicedInfo = {
- 'cardNo': cardNo,
- 'chargeIndex': port,
- }
- orderNo, cardOrderNo = self.record_consume_for_card(card, RMB(coins), servicedInfo=servicedInfo,
- attachParas=attachParas)
- # 记录缓存信息 可以在个人中心以及经销商的端口管理显示
- lineInfo = {
- 'port': port,
- 'cardNo': cardNo,
- 'openId': card.openId,
- 'payCount': 1,
- 'coins': coins,
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- 'orderNo': orderNo,
- 'cardOrderNo': cardOrderNo,
- 'payType': payType,
- 'consumeType': 'card',
- }
- finishedTime = None
- if needTime:
- finishedTime = int(time.time()) + (needTime + 5) * 60
- # lineInfo['needTime'] = needTime
- ServiceProgress.register_card_service(
- self.device,
- port,
- card,
- {
- 'orderNo': orderNo,
- 'coin': VirtualCoin(coins).mongo_amount,
- 'cardOrderNo': cardOrderNo
- },
- finishedTime)
- logger.info('port:{} is running, order:{} cardOrder:{}'.format(port, orderNo, cardOrderNo))
- # 更新端口缓存
- Device.update_port_control_cache(self.device.devNo, lineInfo)
|