123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import logging
- from mongoengine import DoesNotExist
- from typing import TYPE_CHECKING
- from apilib.monetary import RMB
- from apilib.utils_sys import MemcachedLock
- from apps.web.constant import START_DEVICE_STATUS, USER_RECHARGE_TYPE, Const
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.payment import WithdrawGateway
- from apps.web.core.services import StartDeviceEngine
- from apps.web.exceptions import DuplicatedOperationError
- from apps.web.helpers import get_user_manager_agent
- from apps.web.report.ledger import Ledger
- from apps.web.user.models import MyUser, ConsumeRecord, CardRechargeOrder, Card, CardRechargeRecord, RechargeRecord
- from apps.web.user.utils import get_consume_order
- from apps.web.user.utils2 import ConsumeOrderStateEngine, generate_net_payment
- from apps.web.utils import set_start_key_status
- logger = logging.getLogger(__name__)
- if TYPE_CHECKING:
- from apps.web.device.models import GroupDict
- def is_after_ledger(recharge_record):
- # type: (RechargeRecord)->bool
- if not WithdrawGateway.is_ledger(recharge_record.withdraw_source_key):
- return False
- after_ledger = False
- if recharge_record.device.devTypeCode in (
- Const.DEVICE_TYPE_CODE_CAR_CHARGING_CY,
- Const.DEVICE_TYPE_CODE_CHANGING_CY4,
- Const.DEVICE_TYPE_CODE_CAR_CHARGING_CY_V2,
- Const.DEVICE_TYPE_CODE_CHANGING_CY_POWER,
- Const.DEVICE_TYPE_CODE_DUIBIJI,
- Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE,
- Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE_ONLINECARD,
- Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_SIX):
- after_ledger = True
- return after_ledger
- def is_refund_cash(recharge_record, device):
- _refund_cash = False
- if recharge_record.is_temp_package:
- _refund_cash = True
- elif device.devTypeCode in [
- Const.DEVICE_TYPE_CODE_CHANGING_WEIFULE,
- Const.DEVICE_TYPE_CODE_CHANGING_WEIFULE2,
- Const.DEVICE_TYPE_CODE_WEIFULE_MINI,
- Const.DEVICE_TYPE_CODE_WEIFULE_TOUCH_PAD,
- Const.DEVICE_TYPE_CODE_WEIFULE_ANJIAN,
- Const.DEVICE_TYPE_CODE_CHANGING_SOCKET,
- Const.DEVICE_TYPE_CODE_WEIFULE_WASHER
- ]:
- _refund_cash = False
- elif ('refundRMB_device_event' in recharge_record.owner.features) or \
- device.devTypeCode in (
- Const.DEVICE_TYPE_CODE_CAR_CHARGING_CY,
- Const.DEVICE_TYPE_CODE_CHANGING_CY4,
- Const.DEVICE_TYPE_CODE_CAR_CHARGING_CY_V2,
- Const.DEVICE_TYPE_CODE_CHANGING_CY_POWER,
- Const.DEVICE_TYPE_CODE_DUIBIJI,
- Const.DEVICE_TYPE_CODE_CAR_CHARGING_JN,
- Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE,
- Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_FIVE_ONLINECARD,
- Const.DEVICE_TYPE_CODE_CHARGING_CHANGYUAN_SIX
- ):
- _refund_cash = True
- return _refund_cash
- def recharge(user, recharge_record):
- # type: (MyUser, RechargeRecord)->None
- """
- 优惠充值流程
- :param user:
- :param recharge_record:
- :return:
- """
- # 经销商分账
- ledger = Ledger(USER_RECHARGE_TYPE.RECHARGE, recharge_record)
- ledger.execute(stats=True)
- # 用户充值
- user.recharge(money=RMB(recharge_record.money), bestowMoney=RMB(recharge_record.coins - recharge_record.money))
- user.account_recharge(recharge_record)
- def recharge_start_device(user, recharge_record): # type:(MyUser, RechargeRecord) -> None
- """
- 充值启动设备
- 充值并启动设备 实际上还是先充值到用户的余额 然后利用用户的余额直接启动设备
- """
- # 首先还是先给用户充值
- recharge(user, recharge_record)
- orderNo = recharge_record.attachParas.get("orderNo")
- if not orderNo:
- logger.error('[recharge_start_device] recharge order <{}> has no start orderNo'.format(repr(recharge_record)))
- return
- order = get_consume_order(orderNo) # type: ConsumeRecord
- if not order:
- logger.error("[recharge_start_device] recharge order <{}> {} has not find order".format(repr(recharge_record), orderNo))
- # 鉴别不支持启动设备的订单 直接返回
- locker = MemcachedLock(key=order.startLockKey, value='1', expire=180)
- if not locker.acquire():
- logger.error(
- '[_start_device ERROR] cannot get device lock<{}>, openId={}, devNo={}, port={}'.format(order.startLockKey, order.openId, order.devNo, order.port)
- )
- raise DuplicatedOperationError(u'订单运行中 请刷新界面查看订单详情')
- try:
- proxy = StartDeviceEngine(order) # type: StartDeviceEngine
- # 检查订单的支付情况 更多的是余额检验 检验完成之后 根据订单的支付选择 决定是否生成支付信息并添加
- paymentInfo = proxy.get_payment_info()
- paymentInfo and order.update_payment(paymentInfo)
- except ServiceException as se:
- ConsumeOrderStateEngine(order).to_failure(se.result["description"])
- set_start_key_status(start_key=order.orderNo, state=START_DEVICE_STATUS.TIMEOUT)
- return
- # 这个地方只负责将设备的启动传递到新的线程 对于设备启动的结果实际上是未知的
- release_locker = True
- try:
- proxy.start()
- except ServiceException as e:
- logger.info("[_start_device ERROR] service exception = {}".format(e.result))
- set_start_key_status(start_key=order.orderNo, state=START_DEVICE_STATUS.FAILURE)
- except Exception as e:
- logger.exception('[_start_device ERROR](order={}) error={}'.format(order, e))
- set_start_key_status(start_key=order.orderNo, state=START_DEVICE_STATUS.FAILURE)
- finally:
- logger.debug('release_locker = {}'.format(release_locker))
- locker.release()
- def recharge_for_order(user, recharge_record):
- # type: (MyUser, RechargeRecord)->None
- recharge(user, recharge_record)
- try:
- order = get_consume_order(recharge_record.attachParas.get("orderNo"))
- if not order:
- logger.error("[recharge_for_order] no find the order which paid for!!!!!!!")
- return
- # 执行一次订单的扣款
- payment = generate_net_payment(order)
- order.update_payment(payment)
- order.frozen_payer_balance()
- order.clear_payer_frozen()
- ConsumeOrderStateEngine(order).to_finished()
- except Exception as e:
- logger.exception(e)
- def recharge_for_card(user, recharge_record):
- # 经销商分账
- ledger = Ledger(USER_RECHARGE_TYPE.RECHARGE, recharge_record)
- ledger.execute(stats=True)
- # 查找卡
- cardId, cardNo = recharge_record.attachParas["cardId"], recharge_record.attachParas["cardNo"]
- # 创建充值记录
- cardOrder = CardRechargeOrder.new_one(
- openId=recharge_record.openId,
- cardId=cardId,
- cardNo=cardNo,
- money=recharge_record.money,
- coins=recharge_record.coins,
- group=recharge_record.group,
- rechargeId=recharge_record.id
- )
- if cardOrder is None:
- logger.error("[recharge_for_card] create card order error, recharge order = {}".format(recharge_record))
- return
- try:
- card = Card.objects.get(id=cardId)
- except DoesNotExist:
- logger.warning("[recharge_for_card] not find card, card ={}, recharge order = {}".format(cardId, recharge_record))
- return
- # ID卡的 直接充值到卡里面
- if not card.is_id_card:
- return
- status = Card.get_card_status(str(card.id))
- if status == "busy":
- logger.warning("[recharge_for_card] card recharge, card ={}, recharge order = {}".format(cardId, recharge_record))
- return
- Card.set_card_status(str(card.id), 'busy')
- try:
- cardOrder.update_after_recharge_id_card(
- device=recharge_record.device,
- balance=card.balance+cardOrder.coins,
- preBalance=card.balance
- )
- CardRechargeRecord.add_record(
- card=card, group=recharge_record.group, order=cardOrder
- )
- # 卡充值
- card.recharge(cardOrder.chargeAmount, cardOrder.bestowAmount)
- # 统计卡的余额变化
- card.account_recharge(recharge_record)
- except Exception as e:
- logger.exception("[recharge_for_card] recharge id card error, recharge order = {}, error = {}".format(recharge_record, e))
- finally:
- Card.set_card_status(str(card.id), "idle")
- def post_pay(record):
- # type:(RechargeRecord)->None
- try:
- logger.info('post pay for record({})'.format(repr(record)))
- record.reload()
- if not record.owner:
- logger.warning('{} check failure. owner<id={}> is not exist.'.format(repr(record), record.ownerId))
- return
- group = record.group # type: GroupDict
- if not group:
- logger.error('group(%s) is not exist' % record.groupId)
- return
- if group.ownerId != record.ownerId:
- logger.warning('{} check failure. ownerId of record<{}> != ownerId of group<{}>.'.format(
- repr(record), record.ownerId, record.group.ownerId))
- return
- if not record.openId:
- logger.error('openid is null. is not valid record.')
- return
- user = MyUser.objects(openId=record.openId, groupId=record.groupId).first()
- if not user:
- agentId = record.owner.agentId
- product_agent = get_user_manager_agent(record.owner)
- user = MyUser.get_or_create(
- app_platform_type=record.gateway,
- open_id=record.openId,
- group_id=record.groupId,
- **{
- 'agentId': agentId,
- 'productAgentId': str(product_agent.id)
- })
- diff_ts = (datetime.datetime.now() - record.dateTimeAdded).total_seconds()
- logger.debug(
- '{} in ({}) via={} attachParas={} record={} diff={}'.format(
- repr(user), record.gateway, record.via, record.attachParas, repr(record), diff_ts))
- if record.via == USER_RECHARGE_TYPE.RECHARGE:
- return recharge(user, record)
- elif record.via == USER_RECHARGE_TYPE.START_DEVICE:
- return recharge_start_device(user, record)
- elif record.via == USER_RECHARGE_TYPE.RECHARGE_CASH:
- return recharge_for_order(user, record)
- elif record.via == USER_RECHARGE_TYPE.RECHARGE_CARD:
- return recharge_for_card(user, record)
- else:
- logger.error('invalid pay type. recharge record id = %s' % str(record.id))
- except Exception as e:
- logger.exception(e)
|