# -*- 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, CONSUMETYPE 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['data']) if event_data is None: return None if event_data['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['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['fun_code'] in [ic_consume_event_48]: return WEIFULEICCardConsume(self.deviceAdapter, event_data) if event_data['fun_code'] in [power_event_41]: return WEIFULEPowerEvent(self.deviceAdapter, event_data) 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 = consumeRcd.coin package = consumeRcd.package if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get('price') == 0: # 后付费 coins = round(order.get('coins', 1000) * 0.01, 2) 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 = VirtualCoin(0) 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}, ] if consumeRcd.package.get('billingMethod') == CONSUMETYPE.BILL_AS_SERVICE: usedCoins = coins - backCoins titleDictList.append( {u'电量费用': self.device.bill_as_service_feature.current_elec_fee(usedCoins)}) titleDictList.append( {u'服务费': self.device.bill_as_service_feature.current_service_fee(usedCoins)}) 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')