123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import json
- import logging
- import traceback
- from arrow import Arrow
- from django.conf import settings
- from typing import TYPE_CHECKING
- from apilib.monetary import RMB, VirtualCoin
- from apilib.utils_string import make_title_from_dict
- from apps.web.constant import Const, DEALER_CONSUMPTION_AGG_KIND, CONSUMETYPE
- from apps.web.eventer.base import ComNetPayAckEvent, AckEventProcessorIntf, IdStartAckEvent
- from apps.web.user.models import VCardConsumeRecord, ConsumeRecord, RechargeRecord, UserVirtualCard, RefundMoneyRecord
- from apps.web.user.transaction_deprecated import refund_cash
- if TYPE_CHECKING:
- from apps.web.device.models import DeviceDict
- logger = logging.getLogger(__name__)
- class StartAckEventPreProcessor(AckEventProcessorIntf):
- def analysis_reason(self, reason, fault_code=None):
- FINISHED_CHARGE_REASON_MAP = {
- # 服务器定义的停止事件
- 0xC0: u'计费方式无效',
- 0xC1: u'订购套餐已用完',
- 0xC2: u'订购时间已用完',
- 0xC3: u'订购电量已用完',
- 0xC4: u'动态计算功率后, 时间已用完',
- 0xC5: u'订单异常,设备可能离线超过1小时, 平台结单',
- 0xC6: u'系统检测到充电已结束, 平台结单(0x21)',
- 0xC7: u'系统检测到充电已结束, 平台结单(0x15)',
- 0xC8: u'用户远程停止订单',
- 0xC9: u'经销商远程停止订单',
- 0xCA: u'系统检测到订单已结束, 平台结单(0xCA)',
- 0xCB: u'充电时长已达到最大限制(0xCB)',
- 0xCC: u'充电电量已达到最大限制(0xCC)',
- 0xCD: u'设备升级中... 关闭当前订单',
- }
- return FINISHED_CHARGE_REASON_MAP.get(reason, '充电结束')
- def pre_processing(self, device, event_data):
- # type:(DeviceDict, dict)->dict
- source = json.dumps(event_data, indent=4)
- event_data['source'] = source
- if 'duration' in event_data:
- event_data['duration'] = round(event_data['duration'] / 60.0, 1)
- if 'elec' in event_data:
- event_data['elec'] = round(event_data['elec'] / 3600000.0, 3)
- if 'rule' in event_data:
- rule = event_data['rule']
- if 'need_time' in rule:
- event_data['needTime'] = round(rule['need_time'] / 60.0, 2)
- if 'need_elec' in rule:
- event_data['needElec'] = round(rule['need_elec'] / 3600000.0, 3)
- if 'amount' in rule:
- event_data['amount'] = round(rule['amount'] / 100.0, 2)
- if 'need_pay' in event_data:
- if event_data['need_pay'] == -1: # 由服务器计算, 模块计算由精度损失
- event_data['needPay'] = 0.0
- else:
- event_data['needPay'] = round(event_data['need_pay'] / 3600.0 / 100.0, 2)
- if 'status' in event_data and event_data['status'] == 'finished':
- event_data['reasonDesc'] = self.analysis_reason(event_data.get('reason'))
- if event_data.get('duration', 5) < 5 and event_data.get('reason') in [0xC1, 0xC2, 0xC3, 0xC4]:
- event_data['reasonDesc'] = '充电结束(可能为异常导致, 如有疑问, 请联系经销商.)'
- if 'fee' in event_data: # 仅仅是本笔订单的金额,续充单的扣费使用的
- event_data['fee'] = round(event_data['fee'] * 0.01, 2)
- if 'card_id' in event_data:
- event_data['cardNo'] = format(int(event_data['card_id'], 16), 'd')
- if 'sub' in event_data:
- for sub in event_data['sub']:
- if 'fee' in sub:
- sub['fee'] = round(sub['fee'] * 0.01, 2)
- return event_data
- class PolicyComNetPayAckEvent(ComNetPayAckEvent):
- def __init__(self, smartBox, event_data):
- super(PolicyComNetPayAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
- def post_before_start(self, order=None):
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_running': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
- def post_after_start(self, order=None):
- pass
- def post_before_finish(self, order=None):
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_finished': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
- def post_after_finish(self, order=None):
- pass
- def merge_order(self, master_order, sub_orders):
- # type:(ConsumeRecord, list)->dict
- start_time = Arrow.fromdatetime(master_order.startTime, tzinfo=settings.TIME_ZONE)
- port_info = {
- 'start_time': start_time.format(Const.DATETIME_FMT),
- 'estimatedTs': int(start_time.timestamp + 3600 * 12),
- }
- billing_method = self.event_data['billing_method']
- if billing_method == CONSUMETYPE.POSTPAID:
- if 'needTime' in self.event_data:
- port_info.update({
- 'needKind': 'needTime',
- 'needValue': self.event_data['needTime']
- })
- elif 'needElec' in self.event_data:
- port_info.update({
- 'needKind': 'needElec',
- 'needValue': self.event_data['needElec']
- })
- port_info.update({
- 'coins': str(master_order.coin),
- 'consumeType': CONSUMETYPE.POSTPAID,
- })
- else:
- coins = VirtualCoin(master_order.coin)
- for sub_order in sub_orders:
- coins += VirtualCoin(sub_order.coin)
- port_info.update({
- 'coins': coins.mongo_amount,
- 'consumeType': CONSUMETYPE.MOBILE,
- })
- # 免费地址组更新
- master_order.attachParas.get('isFree') and port_info.update({'consumeType': 'isFree'})
- return port_info
- def do_finished_event(self, master_order, sub_orders, merge_order_info):
- # type: (ConsumeRecord, [ConsumeRecord], dict)->None
- billing_method = self.event_data['billing_method']
- if billing_method == CONSUMETYPE.POSTPAID:
- self.do_postpaid_time_finished(master_order, sub_orders, merge_order_info)
- else:
- self.do_prepaid_time_finished(master_order, sub_orders, merge_order_info)
- def insert_vCard_consume_record(self, vCard, order, success, consumeTotal, consumeDay):
- try:
- if success and consumeDay['count'] > 0:
- record = VCardConsumeRecord(
- orderNo=VCardConsumeRecord.make_no(order.logicalCode),
- openId=order.openId,
- nickname=order.nickname,
- cardId=str(vCard.id),
- dealerId=vCard.dealerId,
- devNo=order.devNo,
- devTypeCode = self.device.devTypeCode,
- devTypeName = self.device.devTypeName,
- logicalCode=order.logicalCode,
- groupId=order.groupId,
- address=order.address,
- groupNumber=order.groupNumber,
- groupName=order.groupName,
- attachParas=order.attachParas,
- consumeData=consumeTotal,
- consumeDayData=consumeDay
- )
- record.save()
- except Exception as e:
- logger.exception(e)
- def do_postpaid_time_finished(self, master_order, sub_orders=None, merge_order_info=None):
- duration = self.event_data.get('duration', 0)
- elec = self.event_data.get('elec', 0)
- needPay = VirtualCoin(self.event_data.get('needPay', 0))
- # 套餐最小使用金额
- minFee = VirtualCoin(master_order.package.get('minFee') or 0)
- needPay = max(needPay, minFee)
- # 保护时间判断
- refundProtectionTime = int(self.device.otherConf.get('serverConfigs', {}).get('refundProtectionTime', 5))
- # 免费地址判断
- if duration < refundProtectionTime or master_order.is_free:
- needPay = VirtualCoin(0)
- consumeDict = master_order.servicedInfo
- consumeDict.update({
- 'reason': self.event_data.get('reasonDesc'),
- 'chargeIndex': str(master_order.used_port),
- DEALER_CONSUMPTION_AGG_KIND.DURATION: duration,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: elec,
- })
- logger.debug(
- 'orderNo = {}, orderType = isPostpaid, isFree={} usedTime = {}, needPayMoney = {}'.format(
- master_order.orderNo, master_order.is_free, duration, needPay))
- # 1 获取金币汇率
- coinRatio = float(self.device.otherConf.get('serverConfigs', {}).get('coinRatio', 1))
- # 2 更新订单金额
- master_order.coin = (needPay * coinRatio).mongo_amount
- master_order.money = needPay
- master_order.servicedInfo = consumeDict
- master_order.save()
- # 3 使用金币支付
- self.pay_order(master_order)
- master_order.reload()
- extra = [{u'使用详情': '{}号端口, {}分钟'.format(master_order.used_port, duration)}]
- if master_order.is_free:
- extra.append({u'消费详情': u'免费使用'})
- else:
- if master_order.status == ConsumeRecord.Status.FINISHED:
- if master_order.paymentInfo.get('via') == 'virtualCard':
- desc = u'(已使用优惠卡券抵扣本次消费)'
- master_order.update(coin=VirtualCoin(0), money=RMB(0))
- # 结算完了进行退虚拟卡额度处理:
- try:
- if "rcdId" in master_order.paymentInfo:
- consumeRcdId = master_order.paymentInfo['rcdId']
- else:
- consumeRcdId = master_order.paymentInfo['itemId']
- vCardConsumeRcd = VCardConsumeRecord.objects.get(id=consumeRcdId)
- vCard = UserVirtualCard.objects.get(id=vCardConsumeRcd.cardId)
- vCard.refund_quota(vCardConsumeRcd, duration, 0.0, VirtualCoin(0).mongo_amount)
- except:
- pass
- else:
- desc = u'(已使用账户余额自动结算本次消费)' if needPay > VirtualCoin(0) else ''
- else:
- desc = u'(您的账户余额已不足以抵扣本次消费,请前往账单中心进行支付)'
- self.event_data['reasonDesc'] += desc
- extra.append({u'消费金额': u'{}元'.format(needPay * coinRatio)})
- extra.append({u'用户余额': u'{}元'.format(master_order.user.calc_currency_balance(self.device.owner, self.device.group))})
- self.notify_to_user(master_order.user.managerialOpenId, extra, url=self.device.deviceAdapter.custom_push_url(master_order, master_order.user))
- def notify_to_user(self, openId, extra, url=None):
- group = self.device.group
- self.notify_user_service_complete(
- service_name='充电',
- openid=openId,
- port='',
- address=group['address'],
- reason=self.event_data.get('reasonDesc'),
- finished_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra,
- url=url
- )
- def pay_order(self, order):
- order.status = 'running'
- order.attachParas['packageId'] = order.package.get('packageId')
- order.save()
- order.s_to_e()
- def do_prepaid_time_finished(self, master_order, sub_orders, merge_order_info):
- duration, elec = self.event_data.get('duration', 0), self.event_data.get('elec', 0)
- usedFee = VirtualCoin(self.event_data['needPay'])
- coins = VirtualCoin(merge_order_info['coins'])
- # 保护时间判断
- refundProtectionTime = int(self.device.otherConf.get('serverConfigs', {}).get('refundProtectionTime', 5))
- if duration < refundProtectionTime:
- usedFee = VirtualCoin(0)
- backCoins = coins - usedFee
- logger.debug(
- 'orderNo = {}, orderType = isPostpaid, usedTime = {},coins = {}, usedFee = {}, backCoins = {}'.format(
- master_order.orderNo,
- duration, coins,
- usedFee, backCoins))
- if master_order.is_temp_package:
- extra = [{u'使用详情': '{}号端口, {}分钟(临时套餐)'.format(master_order.used_port, duration)}]
- else:
- extra = [{u'使用详情': '{}号端口, {}分钟'.format(master_order.used_port, duration)}]
- if master_order.paymentInfo['via'] == 'free':
- extra.append({u'消费详情': u'免费使用'})
- elif master_order.paymentInfo['via'] in ['netPay', 'coins', 'cash', 'coin']:
- all_money = RMB(0)
- all_refund_money = RMB(0)
- orders = [master_order] + sub_orders
- for _order in orders[::-1]:
- consumeDict = {
- 'reason': self.event_data.get('reasonDesc'),
- 'chargeIndex': str(master_order.used_port),
- DEALER_CONSUMPTION_AGG_KIND.DURATION: duration,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: elec,
- }
- all_money += RMB(_order.money)
- need_back_coins, need_consume_coins, backCoins = self._calc_refund_info(backCoins, _order.coin)
- isTempPackage = 'isTempPackage' in _order.attachParas
- is_cash = (isTempPackage and _order.package.get('autoRefund', False)) or (
- duration < refundProtectionTime)
- # 临时套餐 + 套餐内退费开关已打开
- if is_cash:
- self.clear_frozen_user_balance(_order, need_back_coins, consumeDict, True)
- all_refund_money += RMB(consumeDict[DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH])
- else:
- self.clear_frozen_user_balance(_order, VirtualCoin(0), consumeDict, True)
- _order.update_service_info(consumeDict)
- if all_refund_money > RMB(0):
- extra.append({u'消费详情': '支付{}元, 退款{}元'.format(all_money, all_refund_money)})
- else:
- extra.append({u'消费详情': '支付{}元'.format(all_money)})
- else:
- logger.error('not net pay rather user virtual card pay. something is wrong.')
- return
- extra.append({u'用户余额': u'{}元'.format(master_order.user.calc_currency_balance(self.device.owner, self.device.group))})
- self.notify_to_user(master_order.user.managerialOpenId, extra)
- def _calc_refund_info(self, backCoins, orderCoin):
- if backCoins >= orderCoin:
- need_back_coins = orderCoin
- need_consume_coins = VirtualCoin(0)
- backCoins -= orderCoin
- else:
- need_back_coins = backCoins
- need_consume_coins = orderCoin - need_back_coins
- backCoins = VirtualCoin(0)
- return need_back_coins, need_consume_coins, backCoins
- def clear_frozen_user_balance(self, order, backCoins, consumeDict, is_cash):
- # type:(ConsumeRecord, VirtualCoin, dict, bool) -> None
- paymentInfo = order.paymentInfo
- if not paymentInfo or paymentInfo['via'] not in ['netPay', 'coins', 'cash', 'coin']:
- raise Exception('method is not this process..')
- payCoins = VirtualCoin(paymentInfo['coins'])
- user = order.user
- if not user:
- logger.error(
- 'refund coins<{}> failure(no found user). consumeRecord = {}'.format(backCoins, repr(order)))
- return
- # 金币做一个保护
- backCoins = min(payCoins, backCoins)
- if backCoins <= VirtualCoin(0):
- if is_cash:
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH: RMB(0).mongo_amount})
- else:
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: RMB(0).mongo_amount})
- logger.error('refund coins<{}>. consumeRecord = {}'.format(backCoins, repr(order)))
- return
- itemId = paymentInfo.get('itemId')
- if itemId:
- rechargeRcd = RechargeRecord.objects.filter(id=itemId, isQuickPay=True, result='success',
- devNo=order.devNo).first()
- else:
- rechargeRcd = None
- if is_cash and rechargeRcd:
- payRMB = RMB(rechargeRcd.money)
- refundRMB = payRMB * (float(backCoins) / float(payCoins))
- # 冻结金额全部扣除
- user.clear_frozen_balance(str(order.id), paymentInfo['deduct'],
- back_coins=VirtualCoin(0),
- consume_coins=VirtualCoin(payCoins))
- try:
- refund_order = refund_cash(
- rechargeRcd, refundRMB, VirtualCoin(0), user = user) # type: RefundMoneyRecord
- if not refund_order:
- logger.error(
- 'refund cash<{}> failure. recharge = {}'.format(refundRMB, repr(rechargeRcd)))
- except Exception:
- logger.exception(traceback.format_exc())
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.REFUNDED_CASH: refundRMB.mongo_amount})
- else:
- user.clear_frozen_balance(str(order.id), paymentInfo['deduct'], back_coins=backCoins,
- consume_coins=(payCoins - backCoins))
- consumeDict.update({DEALER_CONSUMPTION_AGG_KIND.REFUNDED_COINS: backCoins.mongo_amount})
- class PolicyOnlineCardStartAckEvent(IdStartAckEvent):
- def __init__(self, smartBox, event_data):
- super(PolicyOnlineCardStartAckEvent, self).__init__(smartBox, event_data, StartAckEventPreProcessor())
- def post_before_start(self, order=None):
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_running': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
- def post_after_start(self, order=None):
- self.card.reload()
- # 通知用户,已经扣费
- title = make_title_from_dict([
- {u'设备地址': u'{}'.format(self.device.group.address)},
- {u'设备编号': u'{}-{}'.format(self.device['logicalCode'], order.used_port)},
- {u'实体卡': u'{}--No:{}'.format(self.card.cardName or self.card.nickName, self.card.cardNo)},
- {u'本次消费': u'{} 元'.format(order.coin)},
- {u'卡余额': u'{} 元'.format(self.card.balance)},
- ])
- start_time_stamp = self.event_data.get('sts')
- start_time = datetime.datetime.fromtimestamp(start_time_stamp)
- self.notify_user(
- self.card.managerialOpenId,
- 'dev_start',
- **{
- 'title': title,
- 'things': u'刷卡消费',
- 'remark': u'感谢您的支持!',
- 'time': start_time.strftime(Const.DATETIME_FMT),
- 'url': self.deviceAdapter.custom_push_url(order, order.user)
- }
- )
- def post_before_finish(self, order=None):
- # 记录处理的源数据报文
- uart_source = getattr(order, 'uart_source', [])
- uart_source.append({
- 'rece_finished': self.event_data.get('source'),
- 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- })
- order.uart_source = uart_source
- order.save()
- def post_after_finish(self, order=None):
- pass
- def merge_order(self, master_order, sub_orders):
- # type:(ConsumeRecord, list)->dict
- billing_method = self.event_data.get('billing_method')
- start_time = Arrow.fromdatetime(master_order.startTime, tzinfo=settings.TIME_ZONE)
- if billing_method == CONSUMETYPE.POSTPAID:
- portDict = {
- 'coins': '0.0',
- 'money': '0.0',
- 'start_time': start_time.format(Const.DATETIME_FMT),
- 'estimatedTs': int(start_time.timestamp + 3600 * 12),
- 'consumeType': CONSUMETYPE.POSTPAID
- }
- else:
- portDict = {
- 'coins': str(VirtualCoin(self.event_data.get('amount', 0))),
- 'money': str(VirtualCoin(self.event_data.get('amount', 0))),
- 'start_time': start_time.format(Const.DATETIME_FMT),
- 'estimatedTs': int(start_time.timestamp + 3600 * 12),
- 'consumeType': CONSUMETYPE.CARD
- }
- return portDict
- def _do_prepaid_finish(self, order, merge_order_info):
- # type: (ConsumeRecord, dict)->None
- duration, elec = self.event_data.get('duration', 0.0), self.event_data.get('elec', 0.0),
- consumeDict = {
- 'reason': self.event_data.get('reasonDesc', None),
- }
- # 默认状态不退费
- coins = VirtualCoin(self.event_data['amount'])
- useFee = VirtualCoin(self.event_data['amount'])
- backCoins = VirtualCoin(0)
- # 保护时间判断
- refundProtectionTime = int(self.device.otherConf.get('serverConfigs', {}).get('refundProtectionTime', 5))
- auto_refund = self.device.policyTemp.get('forIdcard', {}).get('autoRefund', False)
- if duration < refundProtectionTime:
- useFee = VirtualCoin(0)
- backCoins = coins - useFee
- else:
- if auto_refund:
- useFee = VirtualCoin(self.event_data['needPay'])
- backCoins = coins - useFee
- logger.debug('{} auto refund enable switch is {}, coins={}, backCoins={}'.format(
- repr(self.device), auto_refund, coins, backCoins))
- # 分批塞入订单信息
- master_info = {
- 'order_id': self.event_data['order_id'],
- 'fee': order.coin,
- }
- order_processing_list = [master_info]
- if 'sub' in self.event_data:
- order_processing_list += self.event_data['sub']
- # 订单服务信息与退款处理
- for _info in order_processing_list[::-1]:
- _order = ConsumeRecord.objects.filter(devNo=self.device.devNo, startKey=_info['order_id']).first()
- if not _order:
- continue
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: _order.coin,
- })
- # 全退
- if backCoins >= VirtualCoin(_order.coin):
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: _order.coin.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: _order.coin.mongo_amount,
- })
- self.card.clear_frozen_balance(str(_order.id), _order.coin)
- self.record_refund_money_for_card(_order.coin, str(self.card.id), orderNo=order.orderNo)
- backCoins -= _order.coin
- else: # 部分退
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.CONSUME_CARD: _order.coin.mongo_amount,
- DEALER_CONSUMPTION_AGG_KIND.REFUND_CARD: backCoins.mongo_amount,
- })
- self.card.clear_frozen_balance(str(_order.id), backCoins)
- self.record_refund_money_for_card(backCoins, str(self.card.id), orderNo=order.orderNo)
- backCoins = VirtualCoin(0)
- _order.update_service_info(consumeDict)
- consumeDict.update({
- DEALER_CONSUMPTION_AGG_KIND.DURATION: duration,
- DEALER_CONSUMPTION_AGG_KIND.ELEC: elec,
- # DEALER_CONSUMPTION_AGG_KIND.ELECFEE: self.deviceAdapter.calc_elec_fee(elec),
- })
- order.update_service_info(consumeDict)
- self.card.reload()
- extra = [
- {u'在线卡片': '{}--No:{}'.format(self.card.cardName, self.card.cardNo)},
- {u'使用详情': '{}号端口, {}分钟'.format(order.used_port, duration)}
- ]
- if (coins - useFee) > VirtualCoin(0):
- extra.append({u'消费详情': '支付{}元,退费{}元'.format(coins, coins - useFee)})
- else:
- extra.append({u'消费详情': '支付{}元'.format(coins)})
- extra.append({u'卡片余额': '{}元'.format(self.card.balance.mongo_amount)})
- self.notify_user_service_complete(
- service_name='充电',
- openid=self.card.managerialOpenId,
- port='',
- address=order.address,
- reason=self.event_data.get('reasonDesc'),
- finished_time=order.finishedTime.strftime('%Y-%m-%d %H:%M:%S'),
- extra=extra)
- # 更新一次缓存
- self.deviceAdapter.async_update_portinfo_from_dev()
- def do_finished_event(self, order, merge_order_info):
- # type:(ConsumeRecord, dict)->None
- self._do_prepaid_finish(order, merge_order_info)
- def checkout_order(self, order):
- # 在线卡 执行扣费
- fee = VirtualCoin(order.coin)
- self.card.freeze_balance(transaction_id=str(order.id), fee=fee)
- def _calc_refund_info(self, backCoins, orderCoin):
- if backCoins >= orderCoin:
- need_back_coins = orderCoin
- need_consume_coins = VirtualCoin(0)
- backCoins -= orderCoin
- else:
- need_back_coins = backCoins
- need_consume_coins = orderCoin - need_back_coins
- backCoins = VirtualCoin(0)
- return need_back_coins, need_consume_coins, backCoins
|