1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import json
- import logging
- import time
- import traceback
- from typing import TYPE_CHECKING, Optional, Tuple
- from apilib.monetary import VirtualCoin, RMB, Ratio
- from apilib.utils_string import make_title_from_dict
- from apps.web.constant import Const, START_DEVICE_STATUS, DEALER_CONSUMPTION_AGG_KIND
- from apps.web.core.accounting import Accounting
- from apps.web.device.models import Device, GroupDict, Group, DeviceDict
- from apps.web.device.timescale import FluentedEngine
- from apps.web.eventer.base import WorkEvent
- from apps.web.exceptions import UnifiedConsumeOrderError
- from apps.web.user.constant2 import StartDeviceType
- from apps.web.user.models import ConsumeRecord, UserVirtualCard, MonthlyPackage, ServiceProgress, CardRechargeOrder, \
- Card, CardConsumeRecord, RechargeRecord, RefundMoneyRecord, VCardConsumeRecord
- from apps.web.user.utils2 import generate_card_payment, ConsumeOrderStateEngine, UnifiedCardConsumeOrderManager
- from apps.web.utils import set_start_key_status
- logger = logging.getLogger(__name__)
- 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
- if TYPE_CHECKING:
- pass
- class WeiFuLeStatusEvent(WorkEvent):
- def do(self, **args):
- return self._do_update_charge_status()
- def __translate_status_from_str(self, status):
- dictConf = {
- 'idle': Const.DEV_WORK_STATUS_IDLE,
- 'busy': Const.DEV_WORK_STATUS_WORKING,
- 'forbid': Const.DEV_WORK_STATUS_FORBIDDEN,
- 'fault': Const.DEV_WORK_STATUS_FAULT,
- 'running': Const.DEV_WORK_STATUS_WORKING,
- 'link': Const.DEV_WORK_STATUS_CONNECTED,
- 'estop': Const.DEV_WORK_STATUS_ESTOP,
- 'ready': Const.DEV_WORK_STATUS_READY,
- }
- return dictConf.get(status, Const.DEV_WORK_STATUS_FAULT)
- def _do_update_charge_status(self):
- def do_flush():
- ctrInfo = Device.get_dev_control_cache(self.device.devNo)
- for port, status in port_status.items():
- if str(port) in ctrInfo:
- ctrInfo[str(port)]['status'] = self.__translate_status_from_str(status)
- else:
- ctrInfo[str(port)] = {'status': self.__translate_status_from_str(status)}
- Device.update_dev_control_cache(self.device.devNo, ctrInfo)
- source = self.event_data
- data = source.get('data', {})
- upTime = source.get('time')
- port_status = self.parse_status(data)
- if not upTime or not port_status:
- return
- import time
- now = time.time()
- need_flush = bool((now - upTime) < 10) # 半分钟以内的状态上报为有效上报
- if not need_flush:
- logger.info('Timeout status report!')
- return
- do_flush()
- def parse_status(self, data):
- return data.get('port_status', {})
- class WeiFuLeCommonEvent(object):
- def pay_apps_start_by_32(self, order, callbackSP=None):
- """
- 此函数会对订单进行扣款(补扣或者抢锁扣款,依据上报的事件)
- 一般callbackSP为创建服务进程函数
- """
- consumeRcd = ConsumeRecord.objects.filter(orderNo=order['id']).first()
- # 检查订单是否完成
- if consumeRcd is None or consumeRcd.isNormal:
- logger.info('weifule({}) pay by startAcion..'.format(order['id']))
- return
- # 创建锁
- result = ConsumeRecord.objects.filter(orderNo=order['id'], isNormal=False, attachParas__payBy=None).update(
- attachParas__payBy='event')
- # TODO 抢扣 或者 补扣
- if result:
- package = consumeRcd.package
- attachParas = consumeRcd.attachParas
- group = self.device.group # type: GroupDict
- if group.is_free:
- pass
- # 先寻找是否可用 包月套餐
- monthlyPackage = MonthlyPackage.get_enable_one(
- openId=consumeRcd.openId,
- groupId=consumeRcd.groupId,
- )
- if monthlyPackage:
- monthlyPackage.deduct(consumeRcd)
- elif package.get('name') == '充满自停' and package.get('coins') == 0 and package.get('price') == 0: # 后付费
- consumeRcd.update(isNormal=True, status='')
- else:
- # 虚拟卡查找
- vCardId = attachParas.get('vCardId')
- if vCardId:
- vCard = UserVirtualCard.objects.filter(id=vCardId).first()
- if not vCard:
- consumeRcd.update(isNormal=False, status=START_DEVICE_STATUS.FAILURE,
- errorDesc='没有找到虚拟卡.或虚拟卡已经过期(event)')
- self.deviceAdapter.stop(order['port'])
- vCardConsumeOrder = vCard.consume(openId=consumeRcd.openId, group=group, dev=self.device,
- package=package,
- attachParas=attachParas, nickname=consumeRcd.nickname,
- orderNo=consumeRcd.orderNo)
- if not vCardConsumeOrder:
- # 扣除虚拟卡失败. 设备又启动了, 直接发明了停止掉
- consumeRcd.update(isNormal=False, status=START_DEVICE_STATUS.FAILURE,
- errorDesc='扣除虚拟卡额度的时候,出现异常,请重试(event)')
- logger.info('vCardConsumeOrder error , devNo=<{}> stop port({}) now.'.format(self.device.devNo, order['port'], ))
- return self.deviceAdapter.stop(order['port'])
- else:
- user = consumeRcd.user
- user.update(inc__total_consumed=VirtualCoin(package['coins']))
- user.pay(coins=VirtualCoin(package['coins'])) # 允许有负值
- # 纠正订单信息
- if consumeRcd.status == START_DEVICE_STATUS.FAILURE:
- errorDesc = consumeRcd.errorDesc + "(<{}补充扣款{}币>)".format(
- datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- VirtualCoin(package['coins']).mongo_amount)
- if vCardId:
- errorDesc += '(虚拟卡抵扣)'
- # TODO 补充扣款只扣除金币 所以如果有充值订单 修正订单为金币支付
- consumeRcd.update(isNormal=True,
- status='',
- errorDesc=errorDesc,
- rechargeRcdId='',
- attachParas__lastRechargeRcdId=consumeRcd.rechargeRcdId)
- else:
- consumeRcd.update(isNormal=True,
- status='')
- logger.info('weifule({}) pay by event..'.format(order['id']))
- if callable(callbackSP):
- callbackSP(consumeRcd, order)
- else:
- logger.info('weifule({}) pay by startAcion..'.format(order['id']))
- class WeiFuLePolicyProcess(WorkEvent):
- def translate_reason(self, order):
- return '充电结束'
- @staticmethod
- def _auto_parser_card_no(card_no):
- return card_no if card_no.isdigit() and len(card_no) > 8 else '{}'.format(int(card_no, 16))
- @staticmethod
- def _auto_parser_card_type(card_type):
- if card_type in ['ID', 'online_card']:
- return 'ID'
- elif card_type in ['IC', 'offline_card']:
- return 'IC'
- else:
- return ''
- @staticmethod
- def _notify_card_title(card, order): # type: (Card, dict) -> dict
- if card:
- if card.is_id_card:
- card_title = u'在线卡片'
- elif card.is_ic_card:
- card_title = u'离线卡片'
- else:
- card_title = u'实体卡片'
- return {card_title: u'{}--No.({})'.format(card.cardName or card.nickName, card.cardNo)}
- else:
- 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='',
- address=group['address'],
- reason=self.consumeDict.get('reason'),
- finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- url=self.device.deviceAdapter.custom_push_url(self.consumeRcd, self.consumeRcd.user),
- extra=extra)
- def create_progress_for_socket_order(self, consumeRcd, devInfo):
- try:
- port = int(devInfo['port'])
- progress = ServiceProgress.objects.filter(device_imei=self.device.devNo, port=port,
- devTypeCode=self.device.devTypeCode).first()
- if not progress:
- progress = ServiceProgress(device_imei=self.device.devNo, port=port,
- devTypeCode=self.device.devTypeCode)
- progress.start_time = devInfo['create_time']
- progress.finished_time = devInfo['create_time'] + 60 * 60 * 12
- progress.isFinished = False
- else:
- if devInfo['id'] in progress.consumes:
- return
- if progress.isFinished == False:
- progress.finished_time = progress.finished_time + 60 * 60 * 12
- else:
- progress.consumes = []
- progress.start_time = devInfo['create_time']
- progress.finished_time = devInfo['create_time'] + devInfo.get('amount_time', 60 * 60 * 12)
- progress.isFinished = False
- progress.open_id = consumeRcd.openId
- progress.consumes.append(devInfo['id'])
- progress.status = 'running'
- progress.save()
- except Exception as e:
- logger.exception(e)
- def record_consume_for_card(self, card, money, desc=u'', servicedInfo=None, sid=None, attachParas=None):
- # type: (Card, RMB, unicode, Optional[dict], Optional[str], Optional[dict])->Tuple[ConsumeRecord, CardConsumeRecord]
- group = Group.get_group(self.device['groupId'])
- address = group['address']
- group_number = self.device['groupNumber']
- now = datetime.datetime.now()
- if not servicedInfo:
- servicedInfo = {}
- if not attachParas:
- attachParas = {}
- new_record = ConsumeRecord.objects.create(**{
- 'orderNo': sid,
- 'time': now.strftime('%Y-%m-%d %H:%M:%S'),
- 'dateTimeAdded': now,
- 'openId': card.openId,
- 'nickname': card.nickName,
- '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': desc,
- 'attachParas': attachParas,
- 'servicedInfo': servicedInfo
- })
- # 刷卡消费也记录一条数据
- new_card_record = CardConsumeRecord.objects.create(**{
- 'orderNo': sid,
- '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': desc,
- 'servicedInfo': servicedInfo,
- 'linkedConsumeRcdOrderNo': str(new_record['orderNo'])
- })
- return new_record, new_card_record
- def response_id_card(self):
- """
- 回复ID卡余额查询
- """
- card_no = self.event_data['card_no']
- cardNo = self._auto_parser_card_no(card_no)
- Card.record_dev_card_no(self.device.devNo, cardNo)
- card = self.update_card_dealer_and_type(cardNo)
- resp_message = {'fun_code': self.event_data['fun_code'], 'card_no': card_no, 'balance': 0, 'policy': {}}
- # 如果没有卡,直接返回
- if not card or not card.isBinded:
- resp_message.update({'result': card_not_in_db})
- else:
- if card.frozen:
- resp_message.update({'result': card_is_forzen})
- else:
- # 遇到没有充值的订单 重新充值一次
- card_recharge_order = CardRechargeOrder.get_last_to_do_one(str(card.id))
- if card_recharge_order:
- self.recharge_id_card(card=card, rechargeType='append', order=card_recharge_order)
- card.reload()
- oper = self.event_data.get('reduce')
- if oper:
- result, policy, showBalance = self.generate_Idcard_rules(card)
- resp_message.update({'result': result, 'balance': RMB.yuan_to_fen(showBalance), 'policy': policy})
- else:
- resp_message.update({'result': card_is_normal, 'balance': RMB.yuan_to_fen(card.balance)})
- return self.deviceAdapter.send_mqtt(resp_message)
- def generate_Idcard_rules(self, card):
- _policyTemp = self.device.policyTemp.get('forIdcard', self.deviceAdapter.INIT_POLICY['forIdcard'])
- policyType = _policyTemp.get('policyType')
- billingMethod = _policyTemp.get('billingMethod')
- # 策略计费
- policy = {
- 'type': policyType,
- 'mode': 'price',
- 'auto_stop': True,
- 'over_money_stop': True,
- 'open_id': card.openId,
- 'billingMethod': _policyTemp['billingMethod'],
- 'rule': {}
- }
- if policyType == 'time':
- # 格式化规则
- prices = sorted(_policyTemp.get('rule', {}).get('prices', []), key=lambda _: _['power'])
- for item in prices:
- item['value'] = int(float(item.pop('price')) * 100)
- item['power'] = int(item['power'])
- policy['rule'] = {'time': 'full_stop', 'prices': prices}
- elif policyType == 'elec':
- price = RMB.yuan_to_fen(_policyTemp.get('price', 1))
- policy['rule'] = {'time': 'full_stop', 'price': price}
- else:
- pass
- # 付费时间的不同 导致下发的不同的参数
- if billingMethod == 'prepaid':
- money = _policyTemp['money']
- # 预支付的启动金额不足
- if RMB(money) > RMB(card.balance):
- result = card_less_balance
- showBalance = RMB(card.balance)
- # 预支付的启动金额足够
- else:
- result = card_is_normal
- showBalance = RMB(card.balance) - RMB(money)
- # 获取预支付模式下的自动退款
- auto_refund = _policyTemp.get('autoRefund')
- policy.update({
- 'auto_refund': auto_refund,
- 'money': int(float(money) * 100),
- })
- # 后支付的模式
- elif billingMethod == 'postpaid':
- showBalance = card.balance
- # 对比后支付的最小启动金额
- minAfterStartCoins = _policyTemp.get('minAfterStartCoins')
- if RMB(minAfterStartCoins) > RMB(card.balance):
- result = card_less_balance # 余额不足
- else:
- result = card_is_normal
- policy.update({
- 'auto_refund': False,
- 'money': int(float(card.balance) * 100)
- })
- else:
- result = card_not_in_db
- showBalance = RMB(0)
- return result, policy, showBalance
- def _do_ack_order(self, order):
- funCode = self.event_data['fun_code']
- if funCode in [32, 34]:
- try:
- self.deviceAdapter.ack_event(order['id'], funCode)
- except Exception as e:
- logger.info('ack event devNo=%s err=%s' % (self.device.devNo, e))
- def _do_created_order_32(self, order):
- if order['order_type'] == 'apps_start': # 扫码
- self.pay_apps_start_by_32(order)
- elif order['order_type'] == 'card_start':
- self.pay_card_start_by_32(order)
- elif order['order_type'] == 'coin_start':
- self.pay_coin_start_by_32(order)
- else:
- pass
- logger.info('finished 32 !!order=<{}>'.format(order))
- def _do_exec_order_33(self, order):
- if 'exec_time' in order:
- now = datetime.datetime.fromtimestamp(order['exec_time'])
- elif 'execute_time' in order:
- now = datetime.datetime.fromtimestamp(order['execute_time'])
- else:
- now = datetime.datetime.now()
- ConsumeRecord.objects.filter(orderNo=order['id']).update(startTime=now)
- logger.info('now to exec next order <{}>'.format(order['id']))
- def _do_finished_order_34(self, order):
- # 如果是离线卡的余额回收,修改下余额,然后直接返回即可
- if order['order_type'] == 'card_refund':
- return self.end_for_card_refund(order)
- self.common_verify_order(order)
- if not self.consumeRcd:
- return
- try:
- # 初始化订单的类型(预付费, 后付费)
- self._init_common_info(order)
- self.billingMethod = self.consumeRcd.servicedInfo.get('billingMethod')
- if self.billingMethod == 'postpaid':
- self.finishe_postpaid_process(order)
- elif self.billingMethod == 'prepaid':
- self.finish_prepaid_process(order)
- self.consumeRcd.update_service_info(self.consumeDict)
- else:
- logger.info('No such process.. orderNo={}'.format(self.consumeRcd.orderNo))
- self.notify_to_user(self.consumeRcd.user.managerialOpenId, self.extra)
- logger.info('order is finished.. orderNo={}'.format(self.consumeRcd.orderNo))
- except Exception as e:
- logger.exception('some exception happed,devNo=%s,e=%s' % (self.device.devNo, e))
- finally:
- ctrInfo = Device.get_dev_control_cache(self.device.devNo)
- lineInfo = ctrInfo.get(str(order['port']), {})
- # 如果缓存中要结束的端口是本单的 就清空缓存 否则不处
- if order['id'] == lineInfo.get('orderNo'):
- Device.clear_port_control_cache(self.device.devNo, order['port'])
- def common_verify_order(self, order):
- self.consumeRcd = ConsumeRecord.objects.filter(orderNo=order['id'],
- status__ne='finished').first() # type:ConsumeRecord
- if not self.consumeRcd:
- logger.info('Repeat processing!! orderNo<{}>'.format(order['id']))
- return
- else:
- self.consumeRcd.status = 'finished'
- self.consumeRcd.finishedTime = datetime.datetime.now()
- self.consumeRcd.servicedInfo['source'] = json.dumps(order)
- self.consumeRcd.save()
- if 'card_no' in order:
- cardNo = self._auto_parser_card_no(order['card_no'])
- self.card = self.update_card_dealer_and_type(cardNo=cardNo)
- progress = ServiceProgress.objects.filter(device_imei=self.device.devNo, port=int(order['port']),
- devTypeCode=self.device.devTypeCode,
- consumes__contains=order['id']).first()
- if progress is None:
- pass
- else:
- progress.consumes.remove(order['id'])
- if len(progress.consumes) > 0: # 还有其他的单未处理完成
- progress.save()
- else:
- progress.status = 'finished' # 此时为本次服务的最后一单
- progress.isFinished = True
- progress.save()
- def end_for_card_refund(self, order):
- return self.update_card_dealer_and_type(cardNo=order['card_no'], cardType='IC',
- balance=RMB(order['balance'] / 100.0))
- def _init_common_info(self, order):
- """
- 初始化结束要用到的数据
- """
- self.refundProtectionTime = int(self.device['otherConf'].get('refundProtectionTime', 5))
- self.consumeDict = self.consumeRcd.servicedInfo
- self.duration = round(order['time'] / 60.0, 1)
- self.elec = round(order['elec'] / 1000000.0, 3)
- self.power = round(order.get('power', 0), 1)
- order['reason'] = self.translate_reason(order)
- self.consumeDict.update({'reason': order['reason'], 'duration': self.duration, 'elec': self.elec})
- # 添加一个分档功率
- if self.power:
- self.consumeDict.update({'maxPower': self.power})
- self.extra = [
- {u'使用详情': u'{}分钟(端口: {})'.format(self.duration, self.consumeDict['chargeIndex'])}
- ]
- # 32启动补扣或者刷卡建单 *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
- def pay_apps_start_by_32(self, order, callbackSP=None):
- """
- 此函数会对订单进行扣款(补扣或者抢锁扣款,依据上报的事件)
- 一般callbackSP为创建服务进程函数
- """
- consumeRcd = ConsumeRecord.objects.filter(orderNo=order['id']).first() # type: ConsumeRecord
- # 检查订单是否完成
- if consumeRcd is None or consumeRcd.isNormal:
- logger.info('weifule({}) pay by startAction..'.format(order['id']))
- return
- # 创建锁
- result = ConsumeRecord.objects.filter(
- orderNo=order['id'], isNormal=False, attachParas__payBy=None).update(
- attachParas__payBy='event'
- )
- if not result:
- return
- # TODO 在线支付的抢扣或者补扣
- # 订单为免费的情况 更换状态即可
- if consumeRcd.isFree:
- logger.info("[pay_apps_start_by_32] free order = {}, event = {}".format(consumeRcd, self.event_data))
- consumeRcd.update(isNormal=True, status=START_DEVICE_STATUS.RUNNING)
- return
- # 后支付的情况 更换订单状态即可
- if consumeRcd.package.isPostpaid:
- logger.info("[pay_apps_start_by_32] post paid order = {}, event = {}".format(consumeRcd, self.event_data))
- consumeRcd.update(isNormal=True, status=START_DEVICE_STATUS.RUNNING)
- # 预支付的情况 考虑要补扣金额
- else:
- consumeRcd.frozen_payer_balance()
- # 纠正订单信息
- if consumeRcd.status == START_DEVICE_STATUS.FAILURE:
- errorDesc = consumeRcd.description + "(<{}补充扣款>)".format(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
- consumeRcd.update(isNormal=True, status=START_DEVICE_STATUS.RUNNING, errorDesc=errorDesc)
- else:
- consumeRcd.update(isNormal=True, status=START_DEVICE_STATUS.RUNNING)
- logger.info('weifule({}) pay by event..'.format(order['id']))
- set_start_key_status(start_key=consumeRcd.startKey, state=START_DEVICE_STATUS.FINISHED, order_id=str(consumeRcd.id))
- if callable(callbackSP):
- callbackSP(consumeRcd, order)
- self.create_progress_for_socket_order(consumeRcd, order)
- def pay_card_start_by_32(self, order):
- # 查找卡
- logger.debug("[pay_card_start_by_32] order = {}".format(order))
- cardNo, cardType = self._auto_parser_card_no(order['card_no']), self._auto_parser_card_type(order['card_type'])
- card = self.update_card_dealer_and_type(cardNo, cardType) # type: Card
- # 非法卡
- if not card or not card.isBinded or card.frozen:
- logger.info("[pay_card_start_by_32], not find normal card! order = {}".format(order))
- if card and card.is_id_card:
- self.device.deviceAdapter.stop_charging_port(order["port"])
- return
- # extra = [
- # {u'设备地址': u'{}'.format(self.device.group.address)},
- # {u'设备编号': u'{}'.format(self.device.logicalCode)},
- # self._notify_card_title(card, order)
- # ]
- #
- # 创建订单参数
- data = {
- 'devInfo': {'logicalCode': self.device.logicalCode},
- 'userInfo': {'cardId': str(card.id)},
- }
- # 从policy中构建出套餐参数
- startInfo = {
- 'sequenceNo': order['id'],
- 'startType': StartDeviceType.CARD,
- 'port': order['port'],
- 'packageId': '',
- "name": "刷卡套餐",
- "policyType": order['policy']['type'],
- "autoRefund": order['policy']['auto_refund'],
- "autoStop": order['policy']['auto_stop'],
- "billingMethod": order['policy']['billingMethod'],
- "rules": order['policy']["rule"]
- }
- # 预支付的情况 套餐的金额等于付款的金额
- if startInfo["billingMethod"] == "prepaid":
- startInfo["price"] = RMB.fen_to_yuan(order['policy']['money']) # type:RMB
- # 后支付的情况 套餐金额暂时不变
- else:
- startInfo["price"] = RMB(0) # type:RMB
- data["startInfo"] = startInfo
- # 根据参数组装订单
- try:
- with UnifiedCardConsumeOrderManager(**data) as manager:
- consumeRcd = manager.buildOrder() # type: ConsumeRecord
- except UnifiedConsumeOrderError as ue:
- logger.error("[pay_card_start_by_32] order create order error = {}, order = {}".format(ue, order))
- self.device.deviceAdapter.stop_charging_port(order["port"])
- return
- # 预支付的情况下支付
- if card.is_id_card:
- # 预支付的情况下 进行扣款操作
- if not consumeRcd.isPostPaid:
- try:
- payment = generate_card_payment(consumeRcd)
- if payment:
- consumeRcd.update_payment(payment)
- consumeRcd.frozen_payer_balance()
- if not consumeRcd.isPaid:
- raise ValueError('')
- except Exception as e:
- self.device.deviceAdapter.stop_charging_port(order["port"])
- logger.exception(e)
- result = {
- "deviceStartTime": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(order["create_time"]))
- }
- ConsumeOrderStateEngine(consumeRcd).to_running(result)
- start_time_stamp = order.get('create_time')
- start_time = datetime.datetime.fromtimestamp(start_time_stamp)
- ctrInfo = Device.get_dev_control_cache(self.device.devNo)
- lineInfo = ctrInfo.get(str(order['port']), {})
- if not lineInfo or lineInfo.get('status') == Const.DEV_WORK_STATUS_IDLE:
- lineInfo = {
- 'port': str(order['port']),
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'order_type': 'card_start',
- 'startTime': start_time.strftime('%Y-%m-%d %H:%M:%S'),
- 'orderNo': consumeRcd.orderNo,
- }
- Device.update_port_control_cache(self.device.devNo, lineInfo)
- # 预付费流程 *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
- def finish_prepaid_process(self, order):
- # 中间留着写业务
- self._prepaid_analyze_order_info(order)
- self._prepaid_calc_refund_coins(order)
- # 扫码的退费处理
- if order['order_type'] == 'apps_start':
- self.prepaid_end_for_app_start(order)
- # 刷卡的退费处理
- elif order['order_type'] == 'card_start' and order['card_no']:
- self.prepaid_end_for_card_start(order)
- self._prepaid_analyze_notify_info(order)
- def _prepaid_analyze_order_info(self, order):
- try:
- if order['order_type'] == 'apps_start':
- pass
- elif order['order_type'] == 'card_start':
- pass
- except:
- logger.info(traceback.format_exc())
- def _prepaid_calc_refund_coins(self, order):
- auto_refund = order['policy'].get('auto_refund', False)
- self.backCoins = RMB(0)
- money = VirtualCoin(self.consumeRcd.money)
- minFee = VirtualCoin(self.consumeRcd.package.get('minFee') or 0)
- # 免费地址:
- if self.consumeRcd.is_free:
- pass
- else:
- if self._auto_parser_card_type(order.get('card_type')) == 'IC':
- logger.info(
- 'IC card is not refundable orderNo=<{}> duration=<{}>'.format(self.consumeRcd.orderNo, self.duration))
- return
- if self.duration < self.refundProtectionTime:
- self.backCoins = money
- else:
- usedFee = min(VirtualCoin(order['money'] * 0.01), money) # 做一个使用费用的保护 防止使用金额溢出
- usedFee = max(usedFee, minFee) # 和最小消费做比较 取大的
- if auto_refund:
- self.backCoins = money - usedFee
- logger.info(
- 'REFUND STATUS orderNo=<{}>, auto_refund={}, refundProtectionTime=<{}>, duration=<{}>, backCoins=<{}> minFee=<{}>'.format(
- self.consumeRcd.orderNo, auto_refund, self.refundProtectionTime, self.duration, self.backCoins, minFee
- ))
- def _prepaid_analyze_notify_info(self, order):
- # 消费部分
- if order['order_type'] == 'apps_start':
- if self.consumeDict['policyType'] == 'time':
- self.extra.extend([
- {u'订购套餐': self.consumeDict['needTime']},
- ])
- elif self.consumeDict['policyType'] == 'elec':
- self.extra.extend([
- {u'订购套餐': self.consumeDict['needElec']},
- {u'消耗电量': self.consumeDict['elec']},
- ])
- else:
- pass
- elif order['order_type'] == 'card_start':
- self.extra.append(self._notify_card_title(order))
- else:
- pass
- # 金额部分
- if self.consumeRcd.is_free:
- self.extra.append({u'付费金额': u'免费使用!'})
- else:
- if self.backCoins > RMB(0):
- self.extra.append({u'使用明细': u'支付{}元,退费{}元'.format(self.consumeRcd.money, self.backCoins)})
- else:
- self.extra.append({u'使用明细': u'支付{}元'.format(self.consumeRcd.money, self.backCoins)})
- if order['order_type'] == 'card_start':
- self.extra.append({u'卡片余额': u'{}元'.format(self.card.balance)})
- def prepaid_end_for_app_start(self, order):
- # 如果需要退款,计算退款数据.
- if self.backCoins > RMB(0):
- openId = self.consumeRcd.user.openId
- lineInfo = {'openId': openId}
- refundRMB = RMB(0)
- is_temp_package = self.consumeRcd.is_temp_package
- if is_temp_package and self.consumeRcd.recharge_record_id:
- rechargeRcd = RechargeRecord.objects.filter(id=self.consumeRcd.recharge_record_id,
- openId=openId,
- devNo=self.device.devNo,
- isQuickPay=True,
- groupId=self.device.groupId).first()
- refundRMB = rechargeRcd.money * (self.backCoins.amount / self.consumeRcd.coin.amount)
- lineInfo.update({'rechargeRcdId': self.consumeRcd.recharge_record_id})
- self.refund_net_pay(self.consumeRcd.user, lineInfo,
- refundRMB, self.backCoins, self.consumeDict, is_temp_package)
- def prepaid_end_for_card_start(self, order):
- if not self.card: # 离线卡没有绑定或者在线卡被解绑了
- return
- # 不需要退款,直接返回.在线卡需要退费,离线卡只登记使用记录就OK
- if self.backCoins > RMB(0) and self.card.cardType == 'ID':
- self.refund_money_for_card(self.backCoins, self.card.id)
- self.consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: self.backCoins.mongo_amount
- })
- # 最后维护一次 订单上显示的卡余额
- self.card.reload()
- self.consumeDict.update({
- 'cardBalance': self.card.balance.mongo_amount
- })
- # 后付费流程*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
- def finishe_postpaid_process(self, order):
- self._postpaid_analyze_order_info(order)
- self._postpaid_calc_used_fee(order)
- # 扫码扣除余额
- if order['order_type'] == 'apps_start':
- self.postpay_end_for_app_start(order)
- # 刷卡的扣除余额
- elif order['order_type'] == 'card_start' and order['card_no']:
- self.postpay_end_for_card_start(order)
- self._postpaid_analyze_notify_info(order)
- def _postpaid_analyze_order_info(self, order):
- pass
- def _postpaid_calc_used_fee(self, order):
- self.usedFee = VirtualCoin(order['money'] * 0.01)
- # 最小金额处理
- minFee = VirtualCoin(self.consumeRcd.package.get('minFee') or 0)
- # 免费地址:
- if self.consumeRcd.is_free:
- self.usedFee = VirtualCoin(0)
- else:
- # 使用金额不能超过本单的卡余额
- if self.duration < self.refundProtectionTime:
- self.usedFee = VirtualCoin(0)
- else:
- if order['order_type'] == 'apps_start':
- self.usedFee = max(self.usedFee, minFee)
- elif order['order_type'] == 'card_start':
- pass
- logger.info(
- 'REFUND STATUS orderNo=<{}>, isFree={} usedFee={}, refundProtectionTime=<{}>, duration=<{}> minFee=<{}>'.format(
- self.consumeRcd.orderNo, self.consumeRcd.is_free, self.usedFee, self.refundProtectionTime,
- self.duration, minFee
- ))
- def _postpaid_analyze_notify_info(self, order):
- # 消费部分
- if order['order_type'] == 'apps_start':
- if self.consumeDict['policyType'] == 'time':
- self.extra.extend([
- {u'订购套餐': u'{}'.format(self.consumeDict['needTime'])},
- ])
- elif self.consumeDict['policyType'] == 'elec':
- self.extra.extend([
- {u'订购套餐': u'{}度'.format(self.consumeDict['needElec'])},
- {u'消耗电量': u'{}度'.format(self.consumeDict['elec'])},
- ])
- # 金额部分
- if self.consumeRcd.is_free:
- self.extra.append({u'扣费金额': u'免费使用!'})
- else:
- if self.consumeRcd.status == ConsumeRecord.Status.FINISHED:
- if self.consumeRcd.paymentInfo.get('via') == 'virtualCard':
- desc = u'(已使用优惠卡券抵扣本次消费)'
- else:
- desc = u'(已使用账户余额自动结算本次消费)' if self.usedFee > VirtualCoin(0) else ''
- else:
- desc = u'(您的账户余额已不足以抵扣本次消费,请前往账单中心进行支付)'
- self.consumeDict['reason'] += desc
- self.extra.append({u'消费金额': u'{}元'.format(self.usedFee)})
- self.extra.append(
- {u'用户余额': u'{}元'.format(
- self.consumeRcd.user.calc_currency_balance(self.device.owner, self.device.group))})
- if order['order_type'] == 'card_start':
- self.extra.append(self._notify_card_title(order))
- if self.consumeDict['policyType'] == 'time':
- pass
- elif self.consumeDict['policyType'] == 'elec':
- self.extra.extend([
- {u'消耗电量': '{}度'.format(self.consumeDict['elec'])}
- ])
- else:
- pass
- self.extra.append({u'扣费金额': u'{}元'.format(self.usedFee)})
- self.extra.append({u'卡片余额': u'{}元'.format(self.card.balance)})
- def postpay_end_for_app_start(self, order):
- def pay_order():
- try:
- self.consumeRcd.status = 'running'
- self.consumeRcd.attachParas['packageId'] = self.consumeRcd.package.get('packageId')
- self.consumeRcd.save()
- self.consumeRcd.s_to_e()
- except:
- pass
- # 1 更新订单金额
- self.consumeRcd.coin = self.usedFee
- self.consumeRcd.money = self.usedFee
- self.consumeRcd.servicedInfo = self.consumeDict
- self.consumeRcd.save()
- # 2 去结算
- if self.consumeRcd.is_free:
- pass
- else:
- pay_order()
- self.consumeRcd.reload()
- # 如果结算成功
- if self.consumeRcd.status == ConsumeRecord.Status.FINISHED:
- # 如果结算使用的是虚拟卡
- if self.consumeRcd.paymentInfo.get('via') == 'virtualCard':
- # 虚拟卡抵扣 更新订单金额为0
- self.consumeRcd.update(coin=VirtualCoin(0), money=RMB(0))
- try:
- if "rcdId" in self.consumeRcd.paymentInfo:
- consumeRcdId = self.consumeRcd.paymentInfo['rcdId']
- else:
- consumeRcdId = self.consumeRcd.paymentInfo['itemId']
- vCardConsumeRcd = VCardConsumeRecord.objects.get(id=consumeRcdId)
- vCard = UserVirtualCard.objects.get(id=vCardConsumeRcd.cardId)
- vCard.refund_quota(vCardConsumeRcd, self.duration, 0.0, VirtualCoin(0).mongo_amount)
- except:
- pass
- else:
- pass
- def postpay_end_for_card_start(self, order):
- if not self.card: # 离线卡没有绑定或者在线卡被解绑了
- return
- if self.card.cardType == 'ID':
- self.card.update(dec__balance=self.usedFee)
- self.card.reload()
- # 维护 订单上显示的卡余额
- self.consumeDict.update({
- 'cardBalance': self.card.balance.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: self.usedFee.mongo_amount,
- })
- # 维护一次订单
- self.consumeRcd.update(coin=self.usedFee.mongo_amount, money=self.usedFee.mongo_amount)
- CardConsumeRecord.objects.filter(orderNo=self.consumeRcd.orderNo).update(
- money=self.usedFee.mongo_amount,
- balance=self.card.balance.mongo_amount,
- finishedTime=self.consumeRcd.finishedTime,
- servicedInfo=self.consumeDict
- )
- else:
- # 异常情况 不处理
- pass
- def pay_coin_start_by_32(self, order):
- policy = order.get('policy', {})
- coin = int(policy['money'] * 0.01)
- if coin > 0:
- Accounting.syncOfflineCoin(
- self.device,
- datetime.datetime.fromtimestamp(order['create_time']).strftime('%Y-%m-%d'), coin)
- FluentedEngine().in_put_coins_udp(devNo=self.device.devNo,
- ts=int(time.time()),
- coins=coin,
- mode='uart')
- logger.info('devNo=<{}> This coin=<{}> consumption has been recorded!'.format(self.device.devNo, coin))
- class WeiFuLeCarProcess(object):
- desc_map = {
- 0: '订购已用完',
- 1: '管理员停止',
- 2: '设备故障',
- 3: '充电枪拔除',
- 4: '紧急停止按钮',
- 5: '计量故障',
- 6: '功率过载',
- 7: '电压过载',
- 8: '电流过载',
- 9: '超过单次充电最大时长',
- 10: '设备启动失败',
- 11: '继电器故障',
- 12: '刷卡停止',
- 13: '用户远程停止',
- 14: '经销商远程停止',
- 15: '温度超限'
- }
- CREATED = 'created'
- RUNNING = 'running'
- WAITING = 'wait'
- FINISHED = 'finished'
- END = 'end'
- TIMEOUT = 'timeout'
- FAILURE = 'failure'
- def __init__(self, smartbox):
- self.devNo = smartbox.device.devNo
- self.fun_code = smartbox.event_data.get('fun_code')
- self.order_info = smartbox.event_data.get('order')
- self.dev = smartbox.device # type: DeviceDict
- self.adapter = smartbox.deviceAdapter
- self.smartbox = smartbox
- def _exec_order_33(self):
- start_time = self.order_info.get('exec_time')
- start_time = datetime.datetime.fromtimestamp(start_time)
- order_id = self.order_info.get('id')
- consumeOrder = ConsumeRecord.objects.filter(orderNo=order_id, status__ne=ConsumeRecord.Status.FINISHED).first()
- if not consumeOrder:
- logger.info('no this order')
- return
- consumeOrder.update(startTime=start_time)
- def apps_start(self):
- """
- 'order_type' : 'apps_start',
- 'money' : 1.2388653318201,
- 'id' : '86743505437857520201225084915001',
- 'left_money' : 98.76113466818,
- 'last_clock' : 607.31,
- 'create_time' : 1608857355,
- 'time' : 475.525,
- 'amount' : 100,
- 'elec' : 12388.653318201,
- 'exec_time' : 1608857355,
- 'status' : 'running',
- 'last_ecnt' : 16777128
- """
- dev_stat = self.order_info.get('status')
- order = ConsumeRecord.objects.filter(orderNo=self.order_info['id']).first()
- if not order:
- logger.info('no this order')
- return
- if dev_stat == 'running':
- self._apps_start_do_record_running(dev_stat, order)
- elif dev_stat == 'waiting':
- self._apps_start_do_record_waiting(dev_stat, order)
- elif dev_stat == 'finished':
- self._apps_start_do_record_finished(dev_stat, order)
- def _apps_start_do_record_running(self, dev_stat, order):
- rechargeRcdId = order.rechargeRcdId or ''
- if order.status == self.CREATED: # 让adapter处理
- if 'adapter' in self.order_info: # 服务器过来直接处理
- order.update(status=self.RUNNING)
- else:
- if (time.time() - self.order_info.get('create_time', 0)) > 300:
- ConsumeRecord.objects.filter(id=order.id, status=self.CREATED).update(status=self.RUNNING, isNormal=True)
- elif order.status == self.RUNNING: # 设备上报
- start_time = self.order_info.get('exec_time')
- start_time = datetime.datetime.fromtimestamp(start_time)
- order.update(
- status=self.RUNNING,
- startTime=start_time
- )
- elif order.status == self.WAITING: # 33 上来的wait单变running
- start_time = self.order_info.get('exec_time')
- start_time = datetime.datetime.fromtimestamp(start_time)
- order.update(
- status=self.RUNNING,
- startTime=start_time,
- )
- elif order.status in [self.TIMEOUT, self.FAILURE]: # 此时已经退费,标记为后支付,不做处理
- start_time = self.order_info.get('exec_time') or self.order_info.get('create_time')
- port = self.order_info.get('port')
- start_time = datetime.datetime.fromtimestamp(start_time)
- order.update(
- status=self.RUNNING,
- coin=VirtualCoin(0),
- money=RMB(0),
- startTime=start_time,
- attachParas__payAfterUse=True,
- rechargeRcdId='',
- attachParas__last_refund_rechargeRcdId=rechargeRcdId,
- isNormal=True,
- errorDesc='设备启动已退费, 此单标记为后支付<dev_stat:{}>'.format(dev_stat),
- )
- consumeOrder = {
- 'orderNo': order.orderNo,
- 'coin': 0,
- 'consumeType': 'postpaid',
- }
- self.adapter.register_service_progress(order.openId, order.orderNo, port, consumeOrder, order.attachParas)
- title = make_title_from_dict([
- {u'设备地址': u'{}'.format(self.dev.group.address)},
- {u'设备编号': u'{}'.format(self.dev['logicalCode'])},
- ])
- self.smartbox.notify_user(
- order.user.managerialOpenId,
- 'dev_start',
- **{
- 'title': title,
- 'things': u'您的汽车充电服务已启动',
- 'remark': u'感谢您的支持!',
- 'time': start_time.strftime(Const.DATETIME_FMT)
- }
- )
- elif order.status in [self.FINISHED, self.END]:
- pass
- else:
- logger.info('error order status devStat=<{}>, order=<{}>'.format(dev_stat, order.orderNo))
- def _apps_start_do_record_waiting(self, dev_stat, order):
- # 兼容系统 全改为running单
- rechargeRcdId = order.rechargeRcdId or ''
- if order.status == self.CREATED: # 启动过程服务器中断停留在
- if (time.time() - self.order_info.get('create_time', 0)) > 300:
- ConsumeRecord.objects.filter(id=order.id, status=self.CREATED).update(status=self.RUNNING, isNormal=True)
- elif order.status == self.RUNNING: # 服务器成功启动置为running
- order.update(
- status=self.RUNNING
- )
- elif order.status == self.WAITING: # 重复
- pass
- elif order.status in [self.TIMEOUT, self.FAILURE]: # 此时已经退费,标记为后支付,不做处理
- order.update(
- status=self.RUNNING,
- coin=VirtualCoin(0),
- money=RMB(0),
- attachParas__payAfterUse=True,
- rechargeRcdId='',
- attachParas__last_refund_rechargeRcdId=rechargeRcdId,
- isNormal=True,
- errorDesc='设备启动已退费, 此单标记为后支付<dev_stat:{}>'.format(dev_stat),
- )
- consumeOrder = {
- 'orderNo': order.orderNo,
- 'coin': 0,
- 'consumeType': 'postpaid',
- }
- self.adapter.register_service_progress(order.openId, order.orderNo, consumeOrder, order.attachParas)
- elif order.status in [self.FINISHED, self.END]:
- pass
- def _apps_start_do_record_finished(self, dev_stat, order):
- if order.status == self.CREATED: # 启动过程中服务器出错
- ConsumeRecord.objects.filter(id=order.id, status=self.CREATED).update(status=self.RUNNING, isNormal=True)
- order.reload()
- self.pre_pay(order)
- elif order.status in [self.RUNNING, self.WAITING]: # 正常状态的 或者修正状态的单
- payAfterUse = order.attachParas.get('payAfterUse')
- if payAfterUse:
- self.after_pay(order)
- else:
- self.pre_pay(order)
- elif order.status == self.TIMEOUT: # 设备启动后,100事件先上(该状态为running),210回复改为timeout,后付费处理
- order.update(
- status=self.RUNNING,
- coin=VirtualCoin(0),
- money=RMB(0),
- attachParas__payAfterUse=True,
- rechargeRcdId='',
- attachParas__last_refund_rechargeRcdId=order.rechargeRcdId,
- isNormal=True,
- errorDesc='设备启动已退费, 此单标记为后支付<dev_stat:{}>'.format(dev_stat),
- )
- order.reload()
- self.after_pay(order)
- elif order.status == self.FAILURE: # 状态位置不处理
- pass
- elif order.status in [self.FINISHED, self.END]:
- logger.info('do apps finished --> no order found or repeated submit orderNo:{}'.format(order.orderNo))
- return
- logger.info('apps start event orderNo:{} is over'.format(order))
- def pre_pay(self, order):
- openId = order.openId
- # leftMoney = RMB.fen_to_yuan(self.order_info.get('left_money', 0)) # 传过来的这个值有问题
- amount = RMB.fen_to_yuan(self.order_info.get('amount', 0))
- usedMoney = RMB.fen_to_yuan(self.order_info.get('money'))
- leftMoney = amount - usedMoney
- used_time = round(self.order_info.get('time') / 60.0, 2)
- used_elec = self.order_info.get('elec') / 10.0 ** 6
- reason = self.desc_map.get(self.order_info.get('cause'))
- execTimeStamp = self.order_info.get('exec_time')
- finishedTimeStamp = self.order_info.get('over_time')
- port = self.order_info.get('port')
- finishedTime = datetime.datetime.fromtimestamp(finishedTimeStamp)
- if not execTimeStamp:
- startTime = finishedTime
- else:
- startTime = datetime.datetime.fromtimestamp(execTimeStamp)
- status = self.order_info.get('status')
- consumeDict = {
- DEALER_CONSUMPTION_AGG_KIND.DURATION: '%d' % used_time,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: '%.2f' % used_elec,
- DEALER_CONSUMPTION_AGG_KIND.COIN: amount.mongo_amount,
- 'reason': reason
- }
- order.status = status
- order.startTime = startTime
- order.finishedTime = finishedTime
- order.save()
- user = order.user
- group = Group.get_group(self.dev['groupId'])
- extra = [
- # {u'订单号': '{}'.format(order.orderNo)},
- {u'本次使用时长': '{}(分钟)'.format(used_time)},
- ]
- self.smartbox.notify_user_service_complete(
- service_name='充电',
- openid=user.managerialOpenId if user else '',
- port=port,
- address=group['address'],
- reason=reason,
- finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra
- )
- if order.attachParas.get('is_auto_refund', False):
- recharge_record = None
- if order.rechargeRcdId:
- recharge_record = RechargeRecord.objects(
- id=order.rechargeRcdId, isQuickPay=True).first() # type: RechargeRecord
- if recharge_record:
- refundMoneyRecord = RefundMoneyRecord.objects.filter(openId=openId,
- rechargeObjId=recharge_record.id).first()
- if not refundMoneyRecord:
- self._do_refund_money(recharge_record, order, leftMoney, consumeDict)
- else:
- self._do_refund_coin(order, leftMoney, consumeDict)
- order.update_service_info(consumeDict)
- ServiceProgress.objects.filter(device_imei=self.devNo, weifuleOrderNo=order.orderNo).update(
- isFinished=True, finished_time=int(time.time())
- )
- self.adapter.async_update_portinfo_from_dev()
- def after_pay(self, order):
- """
- 只针对设备下发之后,没有回复的故障单为后付费
- :return:
- """
- used_money = RMB.fen_to_yuan(self.order_info.get('money', 0))
- amount = RMB.fen_to_yuan(self.order_info.get('amount', 0))
- used_time = round(self.order_info.get('time') / 60.0, 2)
- used_elec = self.order_info.get('elec') / 10.0 ** 6
- reason = self.desc_map.get(self.order_info.get('cause'))
- execTimeStamp = self.order_info.get('exec_time')
- finishedTimeStamp = self.order_info.get('over_time')
- port = self.order_info.get('port')
- finishedTime = datetime.datetime.fromtimestamp(finishedTimeStamp)
- if not execTimeStamp:
- startTime = finishedTime
- else:
- startTime = datetime.datetime.fromtimestamp(execTimeStamp)
- consumeDict = {
- DEALER_CONSUMPTION_AGG_KIND.DURATION: '%d' % used_time,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: '%.2f' % used_elec,
- 'reason': reason,
- }
- order.startTime = startTime
- order.finishedTime = finishedTime
- coins = VirtualCoin(order.package.get('coins', 0))
- price = RMB(order.package.get('price'))
- ratio = Ratio(float(used_money) / float(amount))
- order.coin = coins * ratio
- order.money = price * ratio
- if order.money == RMB(0):
- order.coin = VirtualCoin(0)
- order.save()
- extra = [
- # {u'订单号': '{}'.format(order.orderNo)},
- {u'本次使用时长': '{}(分钟)'.format(used_time)},
- ]
- if order.money > RMB(0):
- self._pay_by_coins(order)
- else:
- order.update(status=self.FINISHED)
- order.reload()
- if order.status == self.FINISHED:
- extra.append({u'本单消费金额': '{}金币(已使用账户余额自动结算本次消费)'.format(order.coin.mongo_amount)})
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.COIN: order.coin.mongo_amount})
- else:
- extra.append({u'本单消费金额': '{}元((您的账户余额不足以抵扣本次消费,请前往账单中心进行支付))'.format(order.money.mongo_amount)})
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: order.money.mongo_amount})
- self.smartbox.notify_user_service_complete(
- service_name='充电结束',
- openid=order.user.managerialOpenId,
- port=str(port),
- address=self.dev.group['address'],
- reason=reason,
- finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra
- )
- order.update_service_info(consumeDict)
- ServiceProgress.objects.filter(device_imei=self.devNo, weifuleOrderNo=order.orderNo).update(
- isFinished=True, finished_time=int(time.time())
- )
- def _pay_by_coins(self, order):
- try:
- order.s_to_e()
- except Exception:
- return False
- def _do_refund_money(self, recharge_record, consumeOrder, leftMoney, consumeDict):
- logger.info('now do refund money!')
- coins = consumeOrder.coin
- openId = consumeOrder.openId
- price = recharge_record.money
- user = consumeOrder.user
- refundMoney = RMB(price) * Ratio(float(leftMoney) / float(coins))
- if refundMoney > RMB(price):
- refundMoney = RMB(price)
- if refundMoney > RMB(0):
- self.smartbox.refund_net_pay(user, {'rechargeRcdId': str(recharge_record.id), 'openId': user.openId},
- refundMoney,
- VirtualCoin(0), consumeDict, True)
- title = make_title_from_dict([
- {u'设备地址': u'{}'.format(self.dev.group.address)},
- {u'设备编号': u'{}'.format(self.dev['logicalCode'])},
- ])
- self.smartbox.notify_user(self.smartbox.get_managerialOpenId_by_openId(openId), 'refund_coins', **{
- 'title': title,
- 'backCount': u'金额:%s' % refundMoney,
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
- logger.info('refund cash is successful refundMoney:{}'.format(refundMoney))
- def _do_refund_coin(self, consumeOrder, leftMoney, consumeDict):
- logger.info('now do refund coin !')
- coins = consumeOrder.coin
- openId = consumeOrder.openId
- user = consumeOrder.user
- backCoins = VirtualCoin(coins) * Ratio(float(leftMoney) / float(coins))
- if backCoins > VirtualCoin(coins):
- backCoins = VirtualCoin(coins)
- if backCoins > RMB(0):
- self.smartbox.refund_net_pay(user, {'openId': openId}, RMB(0), backCoins, consumeDict, False)
- title = make_title_from_dict([
- {u'设备地址': u'{}'.format(self.dev.group.address)},
- {u'设备编号': u'{}'.format(self.dev['logicalCode'])},
- ])
- self.smartbox.notify_user(self.smartbox.get_managerialOpenId_by_openId(openId), 'refund_coins', **{
- 'title': title,
- 'backCount': u'金币:%s' % backCoins,
- 'finishTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')})
- # ---------------------刷卡处理-------------------------
- def card_start(self):
- status = self.order_info.get('status')
- if self.fun_code == 32:
- self._card_start_do_record_running_32()
- elif self.fun_code == 34:
- self._card_start_do_record_finished_34()
- elif self.fun_code == 33:
- self._exec_order_33()
- def card_refund(self):
- """
- 离线卡:上报退费 做一次卡余额同步
- """
- status = self.order_info.get('status')
- if self.fun_code == 32:
- if status == 'finished':
- self._card_refund_do_record_finished()
- else:
- pass
- elif self.fun_code == 34:
- if status == 'finished':
- pass
- # self._card_refund_do_record_finished()
- else:
- pass
- def _card_start_do_record_running_32(self):
- # used_money = RMB.fen_to_yuan(self.order_info.get('money', 0))
- # left_money = RMB.fen_to_yuan(self.order_info.get('left_money'))
- amount = RMB.fen_to_yuan(self.order_info.get('amount', 0))
- card_balance = RMB.fen_to_yuan(self.order_info.get('balance'))
- start_time_stamp = self.order_info.get('create_time')
- start_time = datetime.datetime.fromtimestamp(start_time_stamp)
- # used_time = self.order_info.get('time') / 60
- # used_elec = self.order_info.get('elec') / 10 ** 6
- # status = self.order_info.get('status')
- order_id = self.order_info.get('id')
- card_no = self.order_info.get('card_no')
- port = self.order_info.get('port')
- card = Card.objects.filter(cardNo=card_no, cardType='IC', dealerId=self.dev.ownerId).first()
- if not card:
- logger.info('no this card cardNo:{}'.format(card_no))
- return
- # 做一次订单号去重
- order = ConsumeRecord.objects.filter(orderNo=order_id).first()
- if order:
- logger.info('order already exists cardNo:{}, order_id'.format(card_no, order_id))
- return
- servicedInfo = {
- 'cardNo': card_no,
- 'port': port,
- 'cardBalance': card_balance.mongo_amount
- }
- attachParas = {
- 'orderNo': order_id,
- 'chargeIndex': str(port)
- }
- # 记录卡消费记录以及消费记录
- orderNo, cardOrderNo = self.smartbox.record_consume_for_card(card, amount, servicedInfo=servicedInfo,
- attachParas=attachParas)
- consumeOrder = {
- 'orderNo': orderNo,
- 'cardOrderNo': cardOrderNo,
- 'coin': str(amount),
- 'consumeType': 'card',
- }
- self._register_card_service_progress(card, port, consumeOrder, order_id)
- title = make_title_from_dict([
- {u'设备地址': u'{}'.format(self.dev.group.address)},
- {u'设备编号': u'{}'.format(self.dev['logicalCode'])},
- {u'实体卡': u'{}--No:{}'.format(card.cardName or card.nickName, card.cardNo)},
- {u'本次消费': u'{} 元'.format(amount)},
- {u'卡余额': u'{} 元'.format(card_balance)},
- ])
- self.smartbox.notify_user(
- card.managerialOpenId,
- 'dev_start',
- **{
- 'title': title,
- 'things': u'刷卡消费',
- 'remark': u'感谢您的支持!',
- 'time': start_time.strftime(Const.DATETIME_FMT)
- }
- )
- def _card_start_do_record_finished_34(self):
- used_time = round(self.order_info.get('time') / 60.0, 2)
- finishedTimeStamp = self.order_info.get('over_time')
- finishedTime = datetime.datetime.fromtimestamp(finishedTimeStamp)
- execTimeStamp = self.order_info.get('exec_time')
- if not execTimeStamp:
- startTime = finishedTime
- else:
- startTime = datetime.datetime.fromtimestamp(execTimeStamp)
- reason = self.desc_map.get(self.order_info.get('cause'))
- card_no = self.order_info.get('card_no')
- used_elec = self.order_info.get('elec') / 10 ** 6
- card_balance = RMB.fen_to_yuan(self.order_info.get('balance'))
- amount = RMB.fen_to_yuan(self.order_info.get('amount'))
- port = self.order_info.get('port')
- order_id = self.order_info.get('id')
- # left_money = RMB.fen_to_yuan(self.order_info.get('left_money')) #这个值有问题
- used_money = RMB.fen_to_yuan(self.order_info.get('money'))
- left_money = amount - used_money
- consumeOrder = ConsumeRecord.objects.filter(devNo=self.devNo, orderNo=order_id,
- status__ne=ConsumeRecord.Status.FINISHED).first()
- if not consumeOrder:
- logger.info('do card finished --> no order found or repeated submit orderNo:{}'.format(order_id))
- return
- openId = consumeOrder.openId
- consumeOrder.servicedInfo.update({
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: left_money.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: amount.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: (amount - left_money).mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.DURATION: '%d' % used_time,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: '%.2f' % used_elec,
- 'cardBalance': card_balance.mongo_amount,
- 'reason': reason,
- 'cardNo': card_no
- })
- consumeOrder.status = self.FINISHED
- consumeOrder.startTime = startTime
- consumeOrder.finishedTime = finishedTime
- consumeOrder.save()
- ServiceProgress.update_progress_and_consume_rcd(
- self.dev['ownerId'],
- {
- 'open_id': openId,
- 'device_imei': self.devNo,
- 'isFinished': False,
- 'weifuleOrderNo': order_id,
- },
- consumeOrder.servicedInfo,
- progressDict={'isFinished': True, 'finished_time': finishedTimeStamp}
- )
- user = consumeOrder.user
- group = Group.get_group(self.dev['groupId'])
- extra = [
- # {u'订单号': '{}'.format(consumeOrder.orderNo)},
- {u'本次使用时长': '{}(分钟)'.format(used_time)},
- {u'卡片余额': '{}(元)'.format(card_balance)},
- ]
- self.smartbox.notify_user_service_complete(
- service_name='刷卡充电',
- openid=user.managerialOpenId if user else '',
- port=str(port),
- address=group['address'],
- reason=reason,
- finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra
- )
- logger.info('card start event orderNo:{} is over'.format(order_id))
- self.adapter.async_update_portinfo_from_dev()
- def _register_card_service_progress(self, card, port, consumeOrder, weifuleOrderNo=None, attachParas=None):
- return ServiceProgress.objects.create(
- open_id=card.openId,
- device_imei=self.devNo,
- devTypeCode=self.dev.devTypeCode,
- port=port,
- cardId=str(card.id),
- attachParas=attachParas if attachParas else {},
- start_time=int(time.time()),
- finished_time=int(time.time() + 24 * 60 * 60),
- consumeOrder=consumeOrder if consumeOrder else {},
- weifuleOrderNo=weifuleOrderNo,
- ).id
- def _card_refund_do_record_finished(self):
- card_no = self.order_info.get('card_no')
- card_balance = RMB.fen_to_yuan(self.order_info.get('balance'))
- refundMoney = RMB.fen_to_yuan(self.order_info.get('refund'))
- finishedTime = self.order_info.get('over_time')
- finishedTime = datetime.datetime.fromtimestamp(finishedTime).strftime('%Y-%m-%d %H:%M:%S')
- card = self.smartbox.update_card_dealer_and_type(card_no, cardType='IC', balance=card_balance)
- if card:
- logger.info('Card balance sync completed, cardNo:{} , refundMoney:{} ,finishedTime:{}'.format(
- card_no, refundMoney.mongo_amount, finishedTime))
- title = make_title_from_dict([
- {u'设备地址': u'{}'.format(self.dev.group.address)},
- {u'设备编号': u'{}'.format(self.dev['logicalCode'])},
- {u'实体卡': u'{}--No:{}'.format(card.cardName, card.cardNo)},
- {u'卡余额': u'{} 元'.format(card_balance)},
- ])
- self.smartbox.notify_user(
- card.managerialOpenId,
- 'refund_coins',
- **{
- 'title': title,
- 'backCount': u'%s 元' % refundMoney,
- 'finishTime': finishedTime
- }
- )
- else:
- logger.info(
- 'Card balance sync failed, cardNo:{} , refundMoney:{} ,finishedTime:{}'.format(
- card_no, refundMoney.mongo_amount, finishedTime))
|