123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import logging
- import arrow
- from arrow import Arrow
- from django.conf import settings
- from apilib.monetary import RMB
- from apps.web.constant import DEALER_CONSUMPTION_AGG_KIND, APP_TYPE
- from apps.web.eventer import EventBuilder
- from apps.web.eventer.base import WorkEvent, ComNetPayAckEvent, AckEventProcessorIntf
- from apps.web.helpers import get_wechat_auth_bridge
- from apps.web.user.models import MyUser
- logger = logging.getLogger(__name__)
- class builder(EventBuilder):
- def __getEvent__(self, device_event):
- if 'order_id' in device_event:
- if device_event['order_type'] == 'com_start':
- return MyComNetPayAckEvent(self.deviceAdapter, device_event)
- if 'event_type' in device_event:
- return
- class FaseChargeEvent(WorkEvent):
- def do(self, **args):
- pass
- class StartAckEventPreProcessor(AckEventProcessorIntf):
- def analysis_reason(self, reason):
- FINISHED_CHARGE_REASON_MAP = {
- '00': u'人工终止',
- '01': u'自动充满',
- '02': u'后台终止',
- '03': u'故障终止',
- # 服务器定义的停止事件
- -2: u'检测到设备未在充电工作状态,结束本次充电',
- }
- return FINISHED_CHARGE_REASON_MAP.get(reason, reason)
- def analysis_charge_method(self,charge_method):
- MAP = {
- '00': '自动充满',
- '01': '定额充电',
- '02': '定量充电',
- '03': '定时充电',
- '04': '备用',
- '05': '手动充电',
- }
- return MAP.get(charge_method, charge_method)
- def pre_processing(self, device, event_data):
- def cleaning_data(filed, new_filed=None, ratio=1.0,to_int=False):
- if filed in event_data:
- if not new_filed:
- new_filed = filed
- event_data[new_filed] = round(float(event_data.pop(filed, 0))*ratio, 2)
- if to_int:
- event_data[new_filed] = int(event_data[new_filed])
- else:
- logger.info('{} not in event_data '.format(filed))
- cleaning_data('port', 'port', to_int=True)
- cleaning_data('start_soc', 'startSoc', to_int=True)
- cleaning_data('finished_soc', 'finishedSoc', to_int=True)
- cleaning_data('duration', to_int=True)
- cleaning_data('used_money', 'usedMoney', ratio=0.01)
- cleaning_data('start_money', 'startMoney', ratio=0.01)
- cleaning_data('start_elec', 'startElec', ratio=0.01)
- cleaning_data('finished_elec', 'finishedElec', ratio=0.01)
- cleaning_data('used_elec', 'usedElec', ratio=0.01)
- if 'reason' in event_data:
- event_data['reasonDesc'] = self.analysis_reason(event_data['reason'])
- if 'charge_method' in event_data:
- event_data['chargeMethodDesc'] = self.analysis_charge_method(event_data['charge_method'])
- try:
- if 'start_time' in event_data:
- event_data['sts'] = arrow.get(event_data['start_time'], 'YYYY-MM-DD HH:mm:ss', tzinfo = settings.TIME_ZONE).timestamp
- if 'finished_time' in event_data:
- event_data['fts'] = arrow.get(event_data['finished_time'], 'YYYY-MM-DD HH:mm:ss', tzinfo = settings.TIME_ZONE).timestamp
- except Exception:
- pass
- return event_data
- def cleaning_data(self, filed, ratio=1.0):
- pass
- class MyComNetPayAckEvent(ComNetPayAckEvent):
- def __init__(self, smartBox, event_data):
- super(MyComNetPayAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
- def post_after_start(self, order=None):
- pass
- def post_after_finish(self, order=None):
- pass
- def merge_order(self, master_order, sub_orders):
- portDict = {}
- billingMethod = master_order.package.get('billingMethod', 'coins')
- portDict['consumeType'] = billingMethod
- needTime, needElec = self.deviceAdapter._check_package(master_order.package)
- start_time = Arrow.fromdatetime(master_order.startTime, tzinfo=settings.TIME_ZONE)
- portDict = {
- }
- if master_order.paymentInfo['via'] == 'virtualCard':
- portDict.update({
- 'vCardId': master_order.virtual_card_id
- })
- all_coins = master_order.package['coins']
- all_price = master_order.package['price']
- all_consume_time_value = needTime
- all_consume_elec_value = needElec
- for sub_order in sub_orders:
- all_coins += sub_order.package['coins']
- all_price += sub_order.package['price']
- sub_needTime, sub_needElec = self.deviceAdapter._check_package(sub_order.package)
- all_consume_time_value += sub_needTime
- all_consume_elec_value += sub_needElec
- portDict['coins'] = str(0)
- portDict['price'] = str(0)
- portDict['all_consume_time_value'] = str(all_consume_time_value)
- portDict['all_consume_elec_value'] = str(all_consume_elec_value)
- portDict['needKind'] = 'needTime'
- portDict['needValue'] = 999 # 显示充满自停
- portDict['unit'] = u'分钟'
- portDict['estimatedTs'] = int(start_time.timestamp + 720 * 60)
- return portDict
- def do_finished_event(self, master_order, sub_orders, merge_order_info):
- startElec, finishedElec, usedElec = self.event_data.get('startElec'), self.event_data.get('finishedElec'), self.event_data.get('usedElec'),
- startMoney, usedMoney = self.event_data.get('startElec'), self.event_data.get('startElec'),
- duration = self.event_data.get('duration')
- coins = RMB(merge_order_info.get('coins', 0))
- usedFee = RMB(usedMoney)
- consumeDict = {
- 'reason': self.event_data['reasonDesc'],
- 'chargeIndex': str(master_order.used_port),
- DEALER_CONSUMPTION_AGG_KIND.DURATION: duration,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: usedElec,
- DEALER_CONSUMPTION_AGG_KIND.ELECFEE: self.deviceAdapter.calc_elec_fee(usedElec),
- }
- auto_refund = self.device.is_auto_refund
- refundProtectionTime = self.device.get('otherConf', {}).get('deviceConfigs', {}).get('refundProtectionTime',5)
- user = MyUser.objects(openId=master_order.openId,
- groupId=master_order.groupId).first() # type: MyUser
- backCoins = RMB(0)
- if duration < refundProtectionTime:
- backCoins = coins
- usedFee = RMB(0)
- else:
- if auto_refund:
- if coins < usedFee:
- backCoins = coins
- else:
- backCoins = coins - usedFee
- else:
- usedFee = coins
- logger.debug('{} auto refund enable switch is {}, refund protect time = {} backMoney={}'.format(
- repr(self.device), str(auto_refund), refundProtectionTime, backCoins))
- extra = []
- extra.append({u'本次使用时长': u'{}(分钟)'.format(duration)})
- if master_order.paymentInfo['via'] == 'free':
- extra.append({u'消费金额': u'当前设备免费使用'})
- elif master_order.paymentInfo['via'] in ['netPay', 'coins', 'cash', 'coin']:
- extra.append({u'消费金额': '{}(金币)'.format(usedFee)})
- if backCoins > RMB(0):
- extra.append({u'退款金额': '{}(金币)'.format(backCoins)})
- for sub_order in sub_orders[::-1]:
- need_back_coins, need_consume_coins, backCoins = self._calc_refund_info(backCoins, sub_order.coin)
- user.clear_frozen_balance(str(sub_order.id), sub_order.paymentInfo['deduct'], need_back_coins)
- sub_order.update_service_info({
- DEALER_CONSUMPTION_AGG_KIND.COIN: sub_order.coin.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: need_consume_coins.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: need_back_coins.mongo_amount})
- need_back_coins, need_consume_coins, backCoins = self._calc_refund_info(backCoins, master_order.coin)
- user.clear_frozen_balance(str(master_order.id), master_order.paymentInfo['deduct'], need_back_coins)
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.COIN: master_order.coin.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.SPEND_MONEY: need_consume_coins.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: need_back_coins.mongo_amount
- })
- master_order.update_service_info(consumeDict)
- else:
- logger.error('not net pay rather user virtual card pay. something is wrong.')
- return
- auth_bridge = get_wechat_auth_bridge(source=self.device,
- app_type=APP_TYPE.WECHAT_USER_MANAGER)
- self.notify_user_service_complete(
- service_name='充电',
- openid=user.get_bound_pay_openid(auth_bridge.bound_openid_key),
- port=str(master_order.used_port),
- address=master_order.address,
- reason=self.event_data.get('reasonDesc'),
- finished_time=master_order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra)
- def _calc_refund_info(self, backCoins, orderCoin):
- if backCoins >= orderCoin:
- need_back_coins = orderCoin
- need_consume_coins = RMB(0)
- backCoins -= orderCoin
- else:
- need_back_coins = backCoins
- need_consume_coins = orderCoin - need_back_coins
- backCoins = RMB(0)
- return need_back_coins, need_consume_coins, backCoins
|