123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import logging
- import time
- from mongoengine import DoesNotExist
- from apilib.monetary import RMB, VirtualCoin
- from apilib.utils_string import make_title_from_dict
- from apilib.utils_sys import memcache_lock
- from apps.web.constant import FAULT_CODE, FAULT_LEVEL, Const, ErrorCode, DEALER_CONSUMPTION_AGG_KIND
- from apps.web.core.accounting import Accounting
- from apps.web.dealer.models import Dealer
- from apps.web.device.models import WeifuleDeviceOrder, Group, Device
- from apps.web.eventer import EventBuilder
- from apps.web.eventer.base import WorkEvent, FaultEvent
- from apps.web.eventer.weifuleCommon import WeiFuLeCommonEvent
- from apps.web.south_intf.platform import handle_and_notify_event_to_north_ytb
- from apps.web.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, \
- ConsumeRecord, WeifuleCardStamp, Card, CardConsumeRecord, CardRechargeOrder, MyUser, CardRechargeRecord, \
- RechargeRecord
- logger = logging.getLogger(__name__)
- created_order_32 = 32
- executing_order_33 = 33
- finished_order_34 = 34
- id_card_request_35 = 35
- card_recharge_order_37 = 37
- fault_event_overload_38 = 38 # 整机功率过载
- fault_event_relay_39 = 39 # 继电器故障
- fault_event_counter_40 = 40 # 计量芯片故障
- fault_event_mcu_36 = 36 # mcu重启
- power_event_41 = 999 # 待设备实现
- ic_consume_event_48 = 48 # ic卡花钱的时候,会上报此事件
- part_sn_event = 49 # 组件上报相关信息
- 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卡使用
- no_load_code = 7
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- event_data = self.deviceAdapter.analyze_event_data(device_event.get('data', {}))
- if event_data is None:
- return None
- if event_data.get('fun_code') in [created_order_32, executing_order_33, finished_order_34, id_card_request_35,
- card_recharge_order_37]:
- return ChargingWEIFULEWorkEvent(self.deviceAdapter, event_data)
- if event_data.get('fun_code') in [fault_event_mcu_36, fault_event_overload_38, fault_event_relay_39,
- fault_event_counter_40]:
- return WEIFULEFaultEvent(self.deviceAdapter, event_data)
- if event_data.get('fun_code') in [ic_consume_event_48]:
- return WEIFULEICCardConsume(self.deviceAdapter, event_data)
- if event_data.get('fun_code') in [power_event_41]:
- return WEIFULEPowerEvent(self.deviceAdapter, event_data)
- # if infoDict['fun_code'] in [part_sn_event]:
- # return PartWorkEvent(self.deviceAdapter, event_data)
- # class PartWorkEvent(WorkEvent):
- # def do(self):
- # partItem = self.curDevInfo['data']
- # for partName,partInfo in partItem.items():
- # if not partInfo['SN']:
- # continue
- # Part.upsert_part(logicalCode=self.device['devNo'], ownerId=self.device['ownerId'], partNo=partInfo['SN'], partName=partName, partType='9999')
- class WEIFULEPowerEvent(WorkEvent):
- def do(self, **args):
- power = int(self.event_data['power'])
- orderNo = str(self.event_data['orderNo'])
- # PowerInfoManager.instence().append_power(orderNo, power)
- class WEIFULEICCardConsume(FaultEvent):
- def do(self, **args):
- cardNo = str(int(self.event_data['card_no'], 16))
- stamp = self.event_data['stamp']
- isCopy = WeifuleCardStamp.is_copy_card(cardNo, self.device['ownerId'], stamp)
- if isCopy:
- self.event_data.update({
- 'faultName': u'复制卡告警',
- 'faultCode': FAULT_CODE.COPY_CARD,
- 'level': FAULT_LEVEL.CRITICAL,
- 'desc': u'卡号为:%s的卡,极可能是复制卡,建议冻结处理。' % cardNo
- })
- super(WEIFULEICCardConsume, self).do()
- newObj = WeifuleCardStamp(
- cardNo=cardNo,
- dealerId=self.device['ownerId'],
- stamp=str(stamp),
- dateTimeAdded=datetime.datetime.now()
- )
- newObj.save()
- class WEIFULEFaultEvent(FaultEvent):
- def do(self, **args):
- if self.event_data['fun_code'] == fault_event_mcu_36:
- self.event_data.update({
- 'faultName': u'单片机告警',
- 'faultCode': FAULT_CODE.MCU_REBOOT,
- 'level': FAULT_LEVEL.NORMAL,
- 'desc': u'充电主板上的单片机重启。'
- })
- elif self.event_data['fun_code'] == fault_event_relay_39:
- self.event_data.update({
- 'faultName': u'继电器告警',
- 'port': int(self.event_data['port']),
- 'faultCode': FAULT_CODE.RELAY_FAULT,
- 'level': FAULT_LEVEL.CRITICAL,
- 'desc': u'继电器发送粘连。'
- })
- elif self.event_data['fun_code'] == fault_event_counter_40:
- self.event_data.update({
- 'faultName': u'计量芯片告警',
- 'port': int(self.event_data['port']),
- 'faultCode': FAULT_CODE.COUNTER_FAULT,
- 'level': FAULT_LEVEL.CRITICAL,
- 'desc': u'计量芯片获取功率失败。'
- })
- elif self.event_data['fun_code'] == fault_event_overload_38:
- self.event_data.update({
- 'faultName': u'整机功率过载告警',
- 'faultCode': FAULT_CODE.DEV_OVERLOAD,
- 'level': FAULT_LEVEL.FATAL,
- 'desc': u'整机功率超过7500瓦。'
- })
- else:
- pass
- super(WEIFULEFaultEvent, self).do()
- class ChargingWEIFULEWorkEvent(WorkEvent, WeiFuLeCommonEvent):
- # 微付乐的板子:根据设备上报上来的订单,创建正在服务的信息
- def create_progress_for_weifule_order(self, consumeRcd, order):
- try:
- progress = ServiceProgress.objects.filter(weifuleOrderNo=order['id']).first()
- if progress:
- return
- port = int(order['port'])
- attachParas = consumeRcd.attachParas
- needKind, needValue, unit = self.analyse_need_from_package(order)
- consumeOrder = {
- 'orderNo': consumeRcd.orderNo,
- 'coin': consumeRcd.coin.mongo_amount,
- 'money': consumeRcd.money.mongo_amount,
- 'unit': unit,
- 'consumeType': 'mobile_vcard' if u'虚拟卡' in consumeRcd.remarks else 'mobile'
- }
- if needKind:
- consumeOrder.update({needKind: needValue})
- new_service_progress = ServiceProgress(
- open_id=consumeRcd.openId,
- device_imei=consumeRcd.devNo,
- devTypeCode=self.device['devType']['code'],
- port=port,
- attachParas=attachParas if attachParas else {},
- start_time=int(order['create_time']),
- finished_time=int(order['create_time']) + 24 * 60 * 60,
- consumeOrder=consumeOrder,
- weifuleOrderNo=order['id']
- )
- new_service_progress.save()
- except Exception as e:
- logger.exception(e)
- def consume_money_for_ID_card(self, agentId, cardNo, balance, money):
- card = Card.objects.get(agentId=agentId, cardNo=cardNo)
- if card.balance < money:
- card.balance = RMB(0)
- else:
- card.balance = (card.balance - money)
- # card.showBalance = card.balance #只有微付乐是创建订单成功后才真正扣费
- try:
- card.save()
- except Exception as e:
- logger.exception(e)
- return card
- def update_balance_for_IC_card(self, card, balance):
- card.balance = balance
- try:
- card.save()
- except Exception, e:
- pass
- def is_order_accepted(self, orderNo, funCode):
- return True if WeifuleDeviceOrder.objects.filter(orderNo=orderNo, funCode=funCode).count() > 0 else False
- def record_order_event(self, order, funCode):
- newObj = WeifuleDeviceOrder(orderNo=order['id'], funCode=funCode, order=order)
- try:
- newObj.save()
- except Exception, e:
- logger.exception('save order event error=%s' % e)
- pass
- def record_consume_for_card(self, card, money, orderNo):
- group = Group.get_group(self.device['groupId'])
- address = group['address']
- group_number = self.device['groupNumber']
- now = datetime.datetime.now()
- new_record = {
- 'orderNo': orderNo,
- 'time': now.strftime("%Y-%m-%d %H:%M:%S"),
- 'dateTimeAdded': now,
- 'openId': card.openId,
- 'ownerId': self.device['ownerId'],
- 'coin': money.mongo_amount,
- 'money': money.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,
- 'remarks': u'刷卡消费',
- 'errorDesc': '',
- 'sequanceNo': '',
- 'desc': '',
- 'attachParas': {},
- 'servicedInfo': {}
- }
- ConsumeRecord.get_collection().insert_one(new_record)
- # 刷卡消费也记录一条数据
- new_card_record = {
- 'orderNo': orderNo,
- 'openId': card.openId,
- 'cardId': str(card.id),
- 'money': money.mongo_amount,
- 'balance': card.balance.mongo_amount,
- 'devNo': self.device['devNo'],
- 'devType': self.device['devType']['name'],
- 'logicalCode': self.device['logicalCode'],
- 'groupId': self.device['groupId'],
- 'address': address,
- 'groupNumber': group_number,
- 'groupName': group['groupName'],
- 'result': 'success',
- 'remarks': u'刷卡消费',
- 'sequanceNo': '',
- 'dateTimeAdded': datetime.datetime.now(),
- 'desc': '',
- 'servicedInfo': {},
- 'linkedConsumeRcdOrderNo': str(new_record['orderNo'])
- }
- CardConsumeRecord.get_collection().insert(new_card_record)
- return new_record['orderNo'], new_card_record['orderNo']
- def __translate_reason(self, cause, chrmt):
- if cause == 0:
- if chrmt == 'TIME':
- return u'订购时间已经用完。'
- else:
- 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 == 6:
- return u'端口功率过载,系统为了安全,关闭此充电端口。'
- elif cause == 7:
- return u'端口空载。可能是插座松动、充电端口故障、或者充电电池故障。'
- elif cause == 8:
- return u'充满自停。'
- elif cause == 9:
- return u'计量芯片故障'
- elif cause == 20:
- return u'端口功率过小。可能是电池已经充满,也可能是所接负载功率太小'
- return u'充电结束。'
- def deal_with_ic_charge_event(self, msgDict):
- cardNo = str(int(self.event_data['card_no'], 16))
- card = self.update_card_dealer_and_type(cardNo, 'IC')
- if not card:
- return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_not_in_db)
- elif card.frozen:
- return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_is_forzen)
- preBalance = RMB(self.event_data['balance'] / 100.0)
- self.update_balance_for_IC_card(card, preBalance)
- rechargeOrder = CardRechargeOrder.get_last_to_do_one(str(card.id))
- if rechargeOrder:
- self.recharge_ic_card(card=card,
- preBalance=preBalance,
- rechargeType='append',
- order=rechargeOrder,
- need_verify=False)
- else:
- return self.deviceAdapter.response_card_charge_result(self.event_data['card_no'], card_has_not_order)
- def response_id_card(self, msgDict):
- data = msgDict
- cardNo = str(int(data['card_no'], 16))
- Card.record_dev_card_no(self.device['devNo'], cardNo)
- card = self.find_card_by_card_no(cardNo)
- # 如果没有卡,直接返回
- if card is None:
- return self.deviceAdapter.response_card_balance(cardNo=data['card_no'], balance=0, result=card_not_in_db)
- elif card.frozen:
- return self.deviceAdapter.response_card_balance(cardNo=data['card_no'], balance=0, result=card_is_forzen)
- if card.cardType == 'IC': # 如果以前是离线卡,只能用于离线卡,需要提醒用户
- return self.deviceAdapter.response_card_balance(cardNo=data['card_no'], balance=0, result=card_type_is_ic)
- card = self.update_card_dealer_and_type(cardNo, 'ID')
- #: 首先检查订单,并进行充值
- #: 用户首先在手机客户端充值,需要这个时刻刷卡上报事件将充值的订单同步上来
- 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()
- fee = RMB(data['fee'] / 100.0)
- if card.showBalance >= fee:
- result = card_is_normal
- # balance = card.showBalance * 100
- else:
- result = card_less_balance
- # balance = card.showBalance * 100
- if result == card_is_normal:
- card.showBalance -= fee
- self.deviceAdapter.response_card_balance(data['card_no'], card.showBalance, result) # 返回的cardNo为16进制
- # 确定发送成功了,然后再保存到数据库中
- card.save()
- def analyse_need_from_package(self, order):
- needKind, needValue, unit = 'needElec', 0, u'度'
- if order['chrmt'] == 'TIME':
- needKind = 'needTime'
- needValue = order['amount_time'] / 60
- unit = u'分钟'
- else:
- needValue = order['amount_elec'] / 1000000.0
- return needKind, needValue, unit
- def do(self, **args):
- devNo = self.device['devNo']
- funCode = self.event_data['fun_code']
- if funCode == card_recharge_order_37: # 如果是卡充值,直接回复订单
- self.deal_with_ic_charge_event(self.event_data)
- elif funCode == id_card_request_35:
- self.response_id_card(self.event_data)
- else: # 处理任务事件
- order = self.event_data['order']
- logger.info('weifule charging event detected, devNo=%s' % (devNo,))
- with memcache_lock(key='%s-%s-%s-finished' % (devNo, order['id'], funCode), value=1,
- expire=120) as acquired:
- if acquired:
- self.deal_order(devNo, funCode, order, self.event_data)
- def deal_order(self, devNo, funCode, order, msgDict):
- dealer = Dealer.get_dealer(self.device['ownerId'])
- # 开始充电最重要的功能核对订单,以及记录订单。
- # 扫码情况下,需要检查订单,如果订单成功了,就不需要核查,如果订单失败的,需要核查,然后把没有扣的钱扣掉
- # 刷卡情况下,正式把刷卡的钱扣掉,并产生消费的订单。
- # 投币情况下,把投币扣费的记录记录下来即可
- # 首先,统一回复确认报文
- if funCode in [created_order_32, executing_order_33, finished_order_34, id_card_request_35]:
- try:
- self.deviceAdapter.ack_event(order['id'], funCode)
- except Exception, e:
- logger.info('ack event devNo=%s err=%s' % (devNo, e))
- pass
- if funCode == created_order_32 and order['order_type'] != 'card_charge': # 订单创建成功,开始收单,并检查账单
- # 回收余额也会有订单,但是没有端口,不需要处理,直接pass掉
- if order['order_type'] == 'card_refund':
- return
- # 首先把端口状态给刷新掉(虽然是任务在设备上排队的通知,端口肯定是要忙起来的,先搞成忙)
- Device.update_dev_control_cache(self.device['devNo'], {
- str(order['port']): {'status': Const.DEV_WORK_STATUS_WORKING}
- }
- )
- if order['order_type'] == 'coin_start': # 投币,直接记账即可
- Accounting.recordOfflineCoin(self.device,
- int(time.time()),
- int(order.get('coins', 0) * 0.01))
- elif order['order_type'] == 'card_start': # 刷卡
- cardNo = str(int(order['card_no'], 16))
- # 登记下卡相关信息
- if order['card_type'] == 'offline_card':
- card = self.update_card_dealer_and_type(cardNo, 'IC', balance=RMB(order['balance'] / 100.0))
- if card:
- self.update_balance_for_IC_card(card, RMB(order['balance'] / 100.0))
- else:
- return
- # 如果卡冻结了,马上把端口关闭
- if card.frozen:
- logger.info('this card=%s is frozen,so shut down the port which opened by the card' % cardNo)
- self.deviceAdapter.stop_charging_port(order['port'])
- else:
- card = self.update_card_dealer_and_type(cardNo, 'ID')
- balance = card.balance - RMB(order['coins'] / 100.0)
- self.update_card_balance(card, balance)
- # 卡的显示余额同步下
- card.showBalance = card.balance
- card.save()
- fee = RMB(order['coins'] / 100.0)
- # 记录卡消费记录以及消费记录
- orderNo, cardOrderNo = self.record_consume_for_card(card, fee, order['id'])
- # 记录当前服务的progress,便于手机界面查询进度
- needKind, needValue, unit = self.analyse_need_from_package(order)
- consumeDict = {'orderNo': orderNo, 'money': order['coins'] / 100.0, 'coin': order['coins'] / 100.0,
- 'cardOrderNo': cardOrderNo, needKind: needValue, 'unit': unit}
- ServiceProgress.register_card_service_for_weifule(self.device, order['port'], card, consumeDict)
- # 通知用户,已经扣费
- title = make_title_from_dict([
- {u"设备地址": u"{}".format(self.device.group.address)},
- {u"设备编号": u"{}".format(self.device["logicalCode"])},
- {u"实体卡": u"{}--No:{}".format(card.cardName or card.nickName, card.cardNo)},
- {u"本次消费": u"{} 元".format(fee)},
- {u"卡余额": u"{} 元".format(card.balance)},
- ])
- start_time_stamp = order.get("create_time")
- start_time = datetime.datetime.fromtimestamp(start_time_stamp)
- self.notify_user(
- card.managerialOpenId,
- 'dev_start',
- **{
- 'title': title,
- 'things': u'刷卡消费',
- 'remark': u'感谢您的支持!',
- 'time': start_time.strftime(Const.DATETIME_FMT)
- }
- )
- elif order['order_type'] == 'apps_start': # 扫码
- self.pay_apps_start_by_32(order, callbackSP=self.create_progress_for_weifule_order)
- elif order['order_type'] == 'card_charge':
- pass
- # 如果是启动了订单,需要更新端口状态,需要刷新服务状态
- elif funCode == executing_order_33 and order['order_type'] != 'card_charge':
- progress = ServiceProgress.objects.filter(weifuleOrderNo=order['id']).first()
- if (not progress) or (not order.has_key('port')): # 只有卡充值的时候,order才没有port
- return
- Device.update_dev_control_cache(self.device['devNo'], {
- str(order['port']): {
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'openId': progress.open_id,
- 'startTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)
- }
- }
- )
- progress.status = 'running'
- progress.runningTime = datetime.datetime.now()
- progress.save()
- # 订单结束,需要把进行账单核对、记录更新、通知、退费等;
- elif funCode == finished_order_34 and order['order_type'] != 'card_charge':
- # 如果是离线卡的余额回收,修改下余额,然后直接返回即可
- if order['order_type'] == 'card_refund':
- card = Card.objects.filter(agentId=dealer['agentId'], cardNo=str(int(order['card_no'], 16))).first()
- if card is None:
- return
- else:
- card.balance = RMB(order['balance'] / 100.0)
- card.save()
- return
- order['reason'] = self.__translate_reason(order['cause'], order['chrmt'])
- devCache = Device.get_dev_control_cache(self.device['devNo']).get(str(order['port']), {})
- if devCache.get('isAPI', False) is True:
- logger.info('handle api push service, devNo=%s' % self.device['devNo'])
- Device.clear_port_control_cache(devNo, order['port'])
- self.event_data.update({'deviceCode': self.device['logicalCode']})
- return handle_and_notify_event_to_north_ytb(self.device["devNo"], self.event_data)
- progress = ServiceProgress.objects.filter(weifuleOrderNo=order['id']).first()
- if progress is None:
- logger.info('Duplicate data pass....')
- return
- progress.status = 'finished'
- progress.isFinished = True
- progress.save()
- consumeRcd = ConsumeRecord.objects.filter(orderNo=order['id']).first()
- if not consumeRcd: # 投币的不会生成订单
- return
- if consumeRcd.status == 'finished':
- logger.info('Repeat processing!! orderNo<{}>'.format(consumeRcd.orderNo))
- return
- try:
- logger.info('source data saving....')
- consumeRcd.update(source=order, status='finished')
- except:
- logger.info('Failed to save source data')
- pass
- try:
- group = Group.get_group(self.device['groupId'])
- consumeDict = {
- 'reason': order['reason'],
- 'chargeIndex': order['port'],
- 'duration': round(order['time'] / 60.0, 1),
- 'elec': round(order['elec'] / 1000000.0, 2)
- }
- notifyDict = {
- 'service': u'充电服务完成',
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- 'remark': u'谢谢您的支持'
- }
- refundDict = {
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- }
- coins = RMB(order['coins'] / 100.0)
- package = consumeRcd.package
- if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get('price') == 0: # 后付费
- usedFee = VirtualCoin(0)
- usedTime = order['time'] / 60
- if order['chrmt'] == 'TIME':
- leftTime = order['left_time'] / 60 if order['left_time'] > 0 else 0
- actualNeedTime = usedTime + leftTime
- usedFee = VirtualCoin(coins * (float(usedTime) / float(actualNeedTime)))
- elif order['chrmt'] == 'ELEC':
- needElec = order['amount_elec'] / 1000000.0
- usedElec = order['elec'] / 1000000.0
- usedFee = VirtualCoin(coins * (float(usedElec) / float(needElec)))
- cause = int(order.get(u'cause', 0))
- if cause == no_load_code:
- usedFee = VirtualCoin(0)
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: usedFee.mongo_amount
- })
- user = MyUser.objects(openId=consumeRcd.openId, groupId=self.device['groupId']).first()
- if not user:
- return
- try:
- user.pay(coins=usedFee)
- Accounting.recordNetPayCoinCount(devNo)
- user.update(inc__total_consumed=usedFee)
- consumeRcd.update(coin=usedFee.mongo_amount)
- except Exception:
- pass
- user.reload()
- titleDictList = [
- {u'设备编号': self.device['logicalCode']},
- {u'端口': order['port']},
- {u'地址': group['address']},
- {u'结束原因': order['reason']},
- {u'充电时间': u'%s分钟' % round(usedTime, 1)},
- {u'本次服务费用': u'%s币' % usedFee},
- ]
- notifyDict.update(
- {
- 'title': make_title_from_dict(titleDictList)
- }
- )
- # 通知服务结束
- notifyOpenId = user.managerialOpenId if user else ''
- self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
- ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'],
- {'weifuleOrderNo': order['id']},
- consumeDict)
- else:
- backCoins = RMB(0)
- if coins > RMB(consumeRcd.coin):
- coins = RMB(consumeRcd.coin)
- else:
- pass
- refundProtection = self.device['otherConf'].get('refundProtection', 5)
- if order['chrmt'] == 'TIME': # 按照时间计费
- needTime = round(order['amount_time'] / 60.0, 1)
- usedTime = round(order['time'] / 60.0, 1)
- leftTime = order['left_time'] / 60.0 if order['left_time'] > 0 else 0
- leftTimeStr = round(leftTime, 1)
- actualNeedTime = round((usedTime + leftTime), 1)
- consumeDict.update({
- 'needTime': needTime,
- 'leftTime': leftTimeStr,
- 'actualNeedTime': u'动态功率计算为%s分钟' % actualNeedTime,
- })
- titleDictList = [
- {u'设备编号': self.device['logicalCode']},
- {u'端口': order['port']},
- {u'地址': group['address']},
- {u'结束原因': order['reason']},
- {u'订购时间': u'%s分钟' % needTime},
- {u'应充时间': u'%s分钟' % actualNeedTime},
- {u'充电时间': u'%s分钟' % usedTime},
- {u'剩余时间': u'%s分钟' % leftTimeStr}
- ]
- notifyDict.update(
- {
- 'title': make_title_from_dict(titleDictList)
- }
- )
- if int(order.get(u'cause', 0)) == no_load_code or usedTime <= refundProtection: # 判断空载
- backCoins = coins
- else:
- if self.device.is_auto_refund:
- backCoins = coins * (float(leftTime) / float(actualNeedTime))
- titleDictList = [
- {u'设备编号': self.device['logicalCode']},
- {u'端口': order['port']},
- {u'预定时间': u'%s分钟' % needTime},
- {u'应充时间': u'%s分钟' % actualNeedTime},
- {u'充电时间': u'%s分钟' % usedTime},
- {u'剩余时间': u'%s分钟' % leftTimeStr},
- ]
- refundDict.update(
- {
- 'title': make_title_from_dict(titleDictList),
- 'backCount': u'金币:%s' % backCoins
- }
- )
- else:
- needElec = round(order['amount_elec'] / 1000000.0, 2)
- usedTime = round(order['time'] / 60.0, 1)
- usedElec = round(order['elec'] / 1000000.0, 2)
- leftElec = needElec - usedElec if needElec > usedElec else 0.0
- leftElec = round(leftElec, 2)
- titleDictList = [
- {u'设备编号': self.device['logicalCode']},
- {u'端口': order['port']},
- {u'结束原因': order['reason']},
- {u'订购电量': u'%s度' % needElec},
- {u'充电时间': u'%s分钟' % usedTime},
- {u'消耗电量': u'%s度' % usedElec},
- {u'剩余电量': u'%s度' % leftElec},
- ]
- notifyDict.update(
- {
- 'title': make_title_from_dict(titleDictList)
- }
- )
- if int(order.get(u'cause', 0)) == no_load_code or usedTime <= refundProtection: # 判断空载
- backCoins = coins
- else:
- if self.device.is_auto_refund:
- backCoins = coins * (float(leftElec) / float(needElec))
- titleDictList = [
- {u'设备编号': self.device['logicalCode']},
- {u'端口': order['port']},
- {u'结束原因': order['reason']},
- {u'订购电量': u'%s度' % needElec},
- {u'充电时间': u'%s分钟' % usedTime},
- {u'消耗电量': u'%s度' % usedElec},
- {u'剩余电量': u'%s度' % leftElec},
- ]
- refundDict.update(
- {
- 'title': make_title_from_dict(titleDictList),
- 'backCount': u'金币:%s' % backCoins
- }
- )
- logger.info(
- 'REFUND STATUS orderNo=<{}>, refundSwitch={}, refundProtectionTime=<{}>, backCoins=<{}>'.format(
- consumeRcd.orderNo, self.device.is_auto_refund, refundProtection, backCoins.mongo_amount
- ))
- if u'虚拟卡' in consumeRcd.remarks:
- # 退额度
- try:
- vRcd = VCardConsumeRecord.objects.get(orderNo=order['id'])
- vCard = UserVirtualCard.objects.get(id=vRcd.cardId)
- except DoesNotExist, e:
- logger.info('can not find the vCard id = %s' % vRcd.cardId)
- return
- # 通知服务结束
- notifyOpenId = self.get_managerialOpenId_by_openId(vRcd.openId) if vCard else ''
- self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
- # 不需要退款,直接返回,不通知
- if backCoins > RMB(0):
- if order['chrmt'] == 'TIME':
- vCard.refund_quota(vRcd, usedTime, 0.0, backCoins.mongo_amount)
- else:
- vCard.refund_quota(vRcd, 0.0, usedElec, backCoins.mongo_amount)
- # 刷卡的方式
- elif order['order_type'] == 'card_start' and order['card_no']:
- consumeDict.update({
- 'cardNo': str(int(order['card_no'], 16)),
- 'port': order['port'],
- })
- dealer = Dealer.get_dealer(ownerId=self.device['ownerId'])
- card = Card.objects.filter(agentId=dealer['agentId'], cardNo=str(int(order['card_no'], 16))).first()
- if card is None: # 离线卡没有绑定或者在线卡被解绑了
- return
- # 先通知
- notifyOpenId = card.managerialOpenId if card else ''
- self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
- # 不需要退款,直接返回.在线卡需要退费,离线卡只登记使用记录就OK
- if backCoins > RMB(0) and card.cardType == 'ID':
- card = self.refund_money_for_card(RMB(backCoins), card.id)
- card.showBalance = card.balance
- card.save()
- consumeDict.update({'refundedMoney': str(backCoins)})
- self.notify_user(notifyOpenId, 'refund_coins', **refundDict)
- else: # 扫码的
- user = MyUser.objects(openId=consumeRcd.openId, groupId=self.device['groupId']).first()
- if not user:
- return
- # 通知服务结束
- notifyOpenId = user.managerialOpenId if user else ''
- self.notify_user(notifyOpenId, 'service_complete', **notifyDict)
- if backCoins > RMB(0):
- refundCash = 'refundRMB_device_event' in self.device.owner.features
- rechargeRcdId = consumeRcd.rechargeRcdId
- if rechargeRcdId:
- rechargeRcd = RechargeRecord.objects.filter(id=rechargeRcdId, isQuickPay=True).first()
- else:
- rechargeRcd = None
- if refundCash is True and rechargeRcd is not None: # 退现金特征 + 有充值订单
- refundRMB = rechargeRcd.money * (backCoins.amount / coins.amount)
- self.refund_net_pay(user, {'rechargeRcdId': rechargeRcdId, 'openId': user.openId},
- refundRMB, VirtualCoin(0), consumeDict, True)
- refundDict.update({'backCount': u'金额:%s' % refundRMB})
- self.notify_user(notifyOpenId, 'refund_coins', **refundDict)
- else:
- self.refund_net_pay(user, {'openId': user.openId}, RMB(0), backCoins, consumeDict,
- False)
- self.notify_user(notifyOpenId, 'refund_coins', **refundDict)
- ServiceProgress.update_progress_and_consume_rcd(self.device['ownerId'], {'weifuleOrderNo': order['id']},
- consumeDict)
- except Exception, e:
- logger.exception('some exception happed,devNo=%s,e=%s' % (devNo, e))
- finally:
- Device.clear_port_control_cache(devNo, order['port'])
- try:
- self.deviceAdapter.get_port_status_from_dev()
- except:
- pass
- elif funCode == finished_order_34 and order['order_type'] == 'card_charge':
- self.update_card_recharge_for_success_event(order['id'], RMB(order['balance'] / 100.0))
- else:
- pass
- def recharge_ic_card(self, card, preBalance, rechargeType, order, need_verify=True):
- # type:(Card, RMB, str, CardRechargeOrder, bool)->bool
- """
- # rechargeType有两种,一种是用直接覆写overwrite的方式,一种是append追加钱的方式。
- # 不同的的设备,充值的方式还不一样.注意:money是实际用户付的钱,coins是给用户充值的钱,比如付10块(money),充15(coins)。
- :param card:
- :param preBalance:
- :param rechargeType:
- :param order:
- :return:
- """
- if not order or order.coins == RMB(0):
- return False
- status = Card.get_card_status(str(card.id))
- if status == 'busy':
- return False
- Card.set_card_status(str(card.id), 'busy')
- try:
- # IC卡需要下发到设备,设备写卡,把余额打入卡中
- if rechargeType == 'overwrite':
- sendMoney = preBalance + order.coins
- else:
- sendMoney = order.coins
- # 先判断order最近一次充值是否OK. 满足三个条件在认为上次充值成功:
- # 1、操作时间已经超过三天
- # 2、操作结果是串口超时, 即result == 1
- # 3、当前余额大于最后一次充值操作的充值前余额
- if need_verify and len(order.operationLog) > 0:
- log = order.operationLog[-1]
- result = log['result']
- time_delta = (datetime.datetime.now() - log['time']).total_seconds()
- last_pre_balance = RMB(log['preBalance'])
- if (result == ErrorCode.DEVICE_CONN_FAIL or result == ErrorCode.BOARD_UART_TIMEOUT) \
- and (time_delta > 3 * 24 * 3600 or preBalance > last_pre_balance):
- logger.debug('{} recharge verify result is finished.'.format(repr(card)))
- order.update_after_recharge_ic_card(device=self.device,
- sendMoney=sendMoney,
- preBalance=preBalance,
- result=ErrorCode.SUCCESS,
- description=u'充值校验结束')
- # 现将订单状态改为待充值
- CardRechargeRecord.add_record(
- card=card,
- group=Group.get_group(order.groupId),
- order=order,
- device=self.device)
- return False
- if self.device.support_reliable: # 如果是新版本的,只管发,结果根据异步的事件进行处理
- self.deviceAdapter.recharge_card_async(card.cardNo, sendMoney, str(order.id))
- return False
- else:
- operation_result, balance = self.deviceAdapter.recharge_card(card.cardNo, sendMoney, str(order.id))
- order.update_after_recharge_ic_card(device=self.device,
- sendMoney=sendMoney,
- preBalance=preBalance,
- syncBalance=balance,
- result=operation_result['result'],
- description=operation_result['description'])
- if operation_result['result'] != ErrorCode.SUCCESS:
- return False
- if not balance:
- balance = preBalance + order.coins
- CardRechargeRecord.add_record(
- card=card,
- group=Group.get_group(order.groupId),
- order=order,
- device=self.device)
- # 刷新卡里面的余额
- card.balance = balance
- card.lastMaxBalance = balance
- card.save()
- return True
- except Exception as e:
- logger.exception(e)
- return False
- finally:
- Card.set_card_status(str(card.id), 'idle')
|