# -*- coding: utf-8 -*- #!/usr/bin/env python import logging import datetime 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 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.user.models import ServiceProgress, UserVirtualCard, VCardConsumeRecord, \ ConsumeRecord, WeifuleCardStamp, Card, CardConsumeRecord, CardRechargeOrder, MyUser from apps.web.user.transaction_deprecated import refund_money 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卡使用 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['funCode'] in [created_order_32,executing_order_33,finished_order_34,id_card_request_35,card_recharge_order_37]: return WashingWEIFULEWorkEvent(self.deviceAdapter, event_data) if event_data['funCode'] in [ic_consume_event_48]: return WEIFULEICCardConsume(self.deviceAdapter, event_data) if event_data['funCode'] 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 WashingWEIFULEWorkEvent(WorkEvent): #微付乐的板子:根据设备上报上来的订单,创建正在服务的信息 def create_progress_for_weifule_order(self,dev,consumeRcd,order): try: progress = ServiceProgress.objects.filter(weifuleOrderNo = order['id']).first() if progress: return 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=dev['devType']['code'], port=-2, attachParas=attachParas if attachParas else {}, start_time=int(order['createTime']), finished_time=24*60*60, consumeOrder = consumeOrder ) 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 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['data'] 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): return 'needTime',order['needTime']/60000,u'分钟' def do(self, **args): devNo = self.device['devNo'] funCode = self.event_data['funCode'] 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['orderType'] != 'card_charge':#订单创建成功,开始收单,并检查账单 #回收余额也会有订单,但是没有端口,不需要处理,直接pass掉 if order['orderType'] == 'card_refund': return #首先把端口状态给刷新掉(虽然是任务在设备上排队的通知,端口肯定是要忙起来的,先搞成忙) Device.update_dev_control_cache(self.device['devNo'],{'status':Const.DEV_WORK_STATUS_WORKING}) if order['orderType'] == 'coin_start':#投币,直接记账即可 Accounting.recordOfflineCoin(self.device, int(time.time()), int(order['coins'])*100) elif order['orderType'] == 'card_start':#刷卡 cardNo = str(int(order['card_no'],16)) #登记下卡相关信息 if order['card_type'] == 'offline_card': card = self.update_card_dealer_and_type(cardNo, 'IC') 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() else: card = self.update_card_dealer_and_type(cardNo, 'ID') balance = card.balance - RMB(order['coins']) self.update_card_balance(card, balance) #卡的显示余额同步下 card.showBalance = card.balance card.save() fee = RMB(order['coins']) # 记录卡消费记录以及消费记录 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'],'coin': order['coins'],'cardOrderNo': cardOrderNo,needKind:needValue,'unit':unit} ServiceProgress.register_card_service_for_weifule(self.device, -2, card, consumeDict) # 通知用户,已经扣费 self.notify_balance_has_consume_for_card(card, fee) elif order['orderType'] == 'apps_start':#扫码 #检查订单是否失败,如果是失败的,需要纠正为成功,并把用户的余额扣除掉 consumeRcd = ConsumeRecord.objects.filter(orderNo = order['id']).first() if consumeRcd is None or consumeRcd.isNormal: return consumeRcd.isNormal = True consumeRcd.save() if u'虚拟卡' in consumeRcd.remarks: pass#虚拟卡,不管成功与否都已经先扣掉了配额(有些不合理),这里什么都不处理 else: user = MyUser.objects.get(openId = consumeRcd.openId,groupId = consumeRcd.groupId) user.pay(VirtualCoin(order['coins'])) self.create_progress_for_weifule_order(self.device,consumeRcd,order) elif order['orderType'] == 'card_charge': pass #如果是启动了订单,需要更新端口状态,需要刷新服务状态 elif funCode == executing_order_33 and order['orderType'] != 'card_charge': progress = ServiceProgress.objects.filter(weifuleOrderNo = order['id']).first() if not progress: return Device.update_dev_control_cache(self.device['devNo'],{ '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['orderType'] != 'card_charge': Device.update_dev_control_cache(self.device['devNo'],{'status':Const.DEV_WORK_STATUS_IDLE}) #如果是离线卡的余额回收,修改下余额,然后直接返回即可 if order['orderType'] == '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'] = order['reason'] progress = ServiceProgress.objects.filter(weifuleOrderNo = order['id']).first() if progress is None: return progress.status = 'finished' progress.isFinished = True progress.save() consumeRcd = ConsumeRecord.objects.filter(orderNo = order['id']).first() if not consumeRcd:#投币的不会生成订单 return try: group = Group.get_group(self.device['groupId']) consumeDict = { 'reason': order['reason'], } service = u'洗衣服务结束' if order['status'] == 'failed': service = u'订单异常结束。结束原因:%s' % order['reason'] elif order['status'] == 'finished': service = u'订单正常结束' notifyDict = { 'service': service, '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']) titleDictList = [ {u'设备编号':self.device['logicalCode']}, {u'地址':group['address']}, {u'结束原因':order['reason']}, ] notifyDict.update( { 'title': make_title_from_dict(titleDictList) } ) backCoins = coins titleDictList = [ {u'设备编号':self.device['logicalCode']}, {u'付款':u'%s元' % coins}, ] refundDict.update( { 'title':make_title_from_dict(titleDictList), 'backCount': u'金币:%s' % backCoins } ) 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 self.device.is_auto_refund: vCard.refund_quota(vRcd,0,0.0,backCoins.mongo_amount) #刷卡的方式 elif order['orderType'] == 'card_start' and order['card_no']: 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 self.device.is_auto_refund 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 self.device.is_auto_refund and order['desc'] != 0: # 仅仅订单失败,才退款 consumeDict.update({'refundedMoney': str(backCoins)}) refund_money(self.device, backCoins, consumeRcd.openId) 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: pass elif funCode == finished_order_34 and order['orderType'] == 'card_charge': self.update_card_recharge_for_success_event(order['id'],RMB(order['balance']/100.0)) else: pass