# -*- coding: utf-8 -*- # !/usr/bin/env python import copy import datetime import json import logging from typing import TYPE_CHECKING from apilib.monetary import RMB from apilib.utils_string import cn from apilib.utils_sys import MemcachedLock from apps.web.constant import START_DEVICE_STATUS from apps.web.core.exceptions import ServiceException, MqttSubscribeError, ClientServiceTimeOutException from apps.web.exceptions import UserServerException from apps.web.user.models import ConsumeRecord from apps.web.user.utils2 import generate_net_payment, ConsumeOrderStateEngine from apps.web.utils import set_start_key_status logger = logging.getLogger(__name__) if TYPE_CHECKING: from apps.web.device.models import DeviceDict from apps.web.user.models import RefundMoneyRecord # ------------------------ 以下为新增内容 ---------------------------------------------- class PolicyService(object): def __init__(self, order): # type:(ConsumeRecord) -> None self._order = order def handle_verify_order(self): """ 检验订单 """ # 1. 防止支付超时 if self._order.status != self._order.Status.WAIT_CONF: raise ServiceException({"result": 2, "description": u"订单状态异常,请前往个人中心查看订单"}) if self._order.isFree: return # 2. 对订单用户金额做检验 注意 这个地方不使用免费来跳过 因为免费设置在组级别 而费用设置在套餐级别 balance = self._order.user.calc_currency_balance( dealer=self._order.owner, group=self._order.group ) if balance < RMB(0): raise ServiceException({"result": 1002, "description": u"当前账户余额不足,请充值后使用"}) # 临时套餐的最小消费金额为0 if balance < self._order.package.minAfterStartCoins: raise ServiceException({"result": 1002, "description": u"当前套餐账户最小余额为{}元,请充值后使用".format(self._order.package.minAfterStartCoins)}) if self._order.isPostPaid: return try: payment = generate_net_payment(self._order) except UserServerException as e: raise ServiceException({"result": 1002, "description": e.message}) return payment def handle_start_order(self): """ 执行订单 """ return self._order.device.deviceAdapter.start_device_realiable(self._order) def handle_account_order(self): """ 对账单进行扣款动作 """ self._order.frozen_payer_balance() class StartDeviceEngine(object): def __init__(self, order): # type:(ConsumeRecord) -> None self._order = order self._service = self.__get_service() # type: PolicyService def __get_service(self): return PolicyService(self._order) def get_payment_info(self): return self._service.handle_verify_order() def start(self, *args, **kwargs): try: set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.RUNNING) result = self._service.handle_start_order() self._service.handle_account_order() ConsumeOrderStateEngine(self._order).to_running(result) set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.FINISHED) except ClientServiceTimeOutException: # 订单超时状态 此状态订单状态未知 有可能被事件服务器拯救 logger.error("[{} start] order = {}, timeout error".format(self.__class__.__name__, self._order.orderNo)) set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.TIMEOUT) ConsumeOrderStateEngine(self._order).to_timeout(u"网络通信超时") except ServiceException as serviceErr: # 订单失败的状态 绝对的失败 errorMsg = serviceErr.result logger.error("[{} start] order = {}, service error = {}".format(self.__class__.__name__, self._order.orderNo, errorMsg)) set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.FAILURE) ConsumeOrderStateEngine(self._order).to_failure(u"设备启动异常【{}】".format(errorMsg)) except MqttSubscribeError as mqttErr: # 订单失败的状态 绝对的失败 该退钱退钱 errorMsg = u'系统忙无响应,您支付的金币已经退还到您的账户。您可以重试,或者选择其他线路或其他设备(不需要再次支付)。' logger.error("[{} start] order = {}, mqtt error = {}".format(self.__class__.__name__, self._order.orderNo, mqttErr)) set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.FAILURE, reason=cn(errorMsg)) ConsumeOrderStateEngine(self._order).to_failure(u"网络异常") except Exception as err: errorMsg = u'启动过程中有异常发生,您支付的金币已经退还到您的账户。' logger.exception("[{} start] order = {}, error = {}".format(self.__class__.__name__, self._order.orderNo, err)) set_start_key_status(start_key=self._order.orderNo, state=START_DEVICE_STATUS.FAILURE, reason=cn(errorMsg)) ConsumeOrderStateEngine(self._order).to_unknown(u"启动异常") def wrapper_start_device(locker, proxy, *args, **kwargs): # type: (MemcachedLock, StartDeviceEngine, list, dict)->None try: proxy.start(*args, **kwargs) finally: locker.release()