123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303 |
- # coding=utf-8
- import logging
- from django.http import JsonResponse
- from django.views.generic import View
- from typing import TYPE_CHECKING
- import simplejson as json
- from voluptuous import MultipleInvalid
- from apilib.utils_sys import MemcachedLock
- from apps.web.constant import Const, START_DEVICE_STATUS
- from apps.web.core import ROLE
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.services import wrapper_start_device, StartDeviceEngine
- from apps.web.core.utils import JsonOkResponse, JsonErrorResponse, async_operation_no_catch
- from apps.web.device.models import DeviceType
- from apps.web.exceptions import UnifiedConsumeOrderError
- from apps.web.user.models import ConsumeRecord, UserBalanceLog, Card, CardBalanceLog
- from apps.web.user.utils import get_consume_order
- from apps.web.user.utils2 import UnifiedConsumeOrderManager, ConsumeOrderStateEngine, get_paginate
- from apps.web.user.validator2 import unifiedConsumeOrderSchema, startConsumeOrderSchema
- from apps.web.utils import error_tolerate, permission_required, get_start_key_status
- if TYPE_CHECKING:
- from django.core.handlers.wsgi import WSGIRequest
- logger = logging.getLogger(__name__)
- @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"预下单错误,请刷新页面重试"))
- @permission_required(ROLE.myuser)
- def unifiedOrder(request): # type:(WSGIRequest) -> JsonResponse
- """
- 创建消费订单
- """
- payload = json.loads(request.body)
- try:
- data = unifiedConsumeOrderSchema(payload)
- except MultipleInvalid as me:
- return JsonErrorResponse(description=u"启动参数校验异常【】".format(me.path[0]))
- # 解析支付参数 创建支付环境
- try:
- with UnifiedConsumeOrderManager(**data) as manager:
- order = manager.buildOrder()
- except UnifiedConsumeOrderError as ue:
- return JsonErrorResponse(description=ue.message)
- ConsumeOrderStateEngine(order).to_wait_confirm()
- return JsonOkResponse(payload={
- "orderNo": order.orderNo,
- "price": order.price,
- "isFree": order.isFree,
- "isPostPaid": order.isPostPaid,
- "logicalCode": order.logicalCode,
- "package": order.package.showDict
- })
- @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"获取预下单错误,请刷新页面重试"))
- @permission_required(ROLE.myuser)
- def getUnifiedOrder(request):
- orderNo = request.GET.get("orderNo")
- order = get_consume_order(orderNo) # type: ConsumeRecord
- if not order:
- return JsonErrorResponse(u"获取订单失败,请刷新页面重试")
- if order.status != order.Status.WAIT_CONF:
- return JsonErrorResponse(u"订单状态异常,请重新扫码下单")
- balance = order.user.calc_currency_balance(
- dealer=order.owner,
- group=order.group
- )
- return JsonOkResponse(payload={
- "orderNo": order.orderNo,
- "price": order.price,
- "isFree": order.isFree,
- "balance": balance,
- "isPostPaid": order.isPostPaid,
- "logicalCode": order.logicalCode,
- "package": order.package.showDict
- })
- @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"启动设备异常,请刷新页面重试"))
- @permission_required(ROLE.myuser)
- def startAction(request):
- """
- 启动设备
- """
- payload = json.loads(request.body)
- try:
- data = startConsumeOrderSchema(payload)
- except MultipleInvalid as me:
- return JsonErrorResponse(description=u"启动参数校验异常【】".format(me.path[0]))
- order = get_consume_order(data["orderNo"]) # type: ConsumeRecord
- if not order:
- logger.warning('[_start_device ERROR] cannot get order, order = {}'.format(data))
- return JsonErrorResponse(description=u"启动参数校验异常【订单查询失败】")
- # 启动锁,防止用户对同一笔订单重复下单并且支付
- lockKey = order.startLockKey
- logger.info(
- '[_start_device] user({}) on device(devNo={}, port={}) lockKey={}, order={}'.format(
- order.openId, order.devNo, order.port, lockKey, order
- )
- )
- locker = MemcachedLock(key=lockKey, value='1', expire=180)
- if not locker.acquire():
- logger.error(
- '[_start_device ERROR] cannot get device lock<{}>, openId={}, devNo={}, port={}'.format(lockKey, order.openId, order.devNo, order.port)
- )
- return JsonErrorResponse(description=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"])
- return JsonResponse(se.result)
- # 这个地方只负责将设备的启动传递到新的线程 对于设备启动的结果实际上是未知的
- release_locker = True
- try:
- async_operation_no_catch(wrapper_start_device, locker, proxy)
- release_locker = False
- except ServiceException as e:
- logger.info("[[_start_device ERROR] service exception = {}]".format(e.result))
- return JsonResponse(e.result)
- except Exception as e:
- logger.exception('[_start_device ERROR](order={}) error={}'.format(order, e))
- return JsonResponse({'result': 0, 'description': u'系统开小差了,请您重新试试吧', 'payload': {}})
- else:
- return JsonResponse({'result': 1, 'description': u'等待设备启动', 'payload': {
- 'outTradeNo': order.orderNo, 'orderType': 'consume', 'adShow': order.owner.ad_show
- }})
- finally:
- logger.debug('release_locker = {}'.format(release_locker))
- release_locker and locker.release()
- @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"获取服务异常"))
- @permission_required(ROLE.myuser)
- def getCurrentUse(request): # type: (WSGIRequest) -> JsonResponse
- openId = request.user.openId
- orderId = request.GET.get("orderId")
- pageIndex = int(request.GET.get("pageIndex", 1))
- pageSize = int(request.GET.get("pageSize", 10))
- query = ConsumeRecord.objects.filter(
- openId=openId,
- status__in=[
- ConsumeRecord.Status.RUNNING, ConsumeRecord.Status.END
- ]
- )
- if orderId:
- query = query.filter(id=orderId)
- dataList = list()
- for order in query.skip((pageIndex-1)*pageSize).limit(pageSize): # type: ConsumeRecord
- device = order.device
- data = {
- 'startTime': order.service.deviceStartTime,
- 'address': order.address,
- 'groupName': order.groupName,
- 'devType': order.devTypeName,
- 'devTypeCode': order.devTypeCode,
- 'logicalCode': order.logicalCode,
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'devNo': order.devNo,
- 'majorDeviceType': device.majorDeviceType,
- 'port': order.port
- }
- # 添加功率曲线
- if 'show_PG_to_user' in device.owner.features and device.support_power_graph and order.port:
- data.update({'showPG': True, 'port': order.port})
- # 添加各种按钮
- data.update(DeviceType.get_services_button(device['devType']['id']))
- # 添加端口的使用详情
- curInfo = device.deviceAdapter.get_port_using_detail(order.port, {})
- data.update(curInfo)
- dataList.append(data)
- return JsonOkResponse(payload={
- 'total': pageSize * pageIndex,
- "dataList": dataList
- }
- )
- class GetCurrentOrder(View):
- @staticmethod
- def _get_response(orderProcessing, succeeded, desc='', record = None):
- record = record or {}
- return JsonOkResponse(
- payload = {
- 'orderProcessing': orderProcessing,
- 'succeeded': succeeded,
- 'desc': desc,
- 'record': record
- }
- )
- def _get_not_yet_response(self):
- return self._get_response(orderProcessing=True, succeeded=None)
- def _get_stop_polling_unknown(self, desc=None):
- desc = desc or u"系统异常"
- return self._get_response(orderProcessing=False, succeeded=False, desc=desc)
- def _get_polling_finished_failed(self, desc, record=None):
- return self._get_response(orderProcessing=False, succeeded=False, desc=desc, record=record)
- def _get_polling_finished_success(self, desc, record):
- return self._get_response(orderProcessing=False, succeeded=True, desc=desc, record=record)
- def get(self, request):
- orderNo = request.GET.get("startKey")
- exp = request.GET.get("exp", 0)
- start_key_status = get_start_key_status(orderNo)
- # 先查找失败的 如果订单状态为失败 直接返回不用访问数据库
- if start_key_status:
- state = start_key_status['state']
- if state in [START_DEVICE_STATUS.FAILURE]:
- return self._get_polling_finished_failed(
- start_key_status['reason']
- )
- # 其余的状态
- if state not in [START_DEVICE_STATUS.FINISHED]:
- if exp < 2 * 60 * 1000:
- return self._get_not_yet_response()
- order = get_consume_order(orderNo)
- if not order:
- return self._get_polling_finished_failed(u'订单查询失败')
- if order.status == order.Status.WAIT_CONF:
- return self._get_not_yet_response()
- # 不需要根据状态进行判断了 直接判断设备有无启动即可
- if order.service.deviceStartTime:
- return self._get_polling_finished_success(
- desc=u'您已成功启动设备。如果有疑问,请点击右下角"设备无反应"按钮',
- record={'coins': order.price, 'detailLink': order.detail_link}
- )
- else:
- return self._get_polling_finished_failed(
- desc=order.description,
- record={'coins': order.price, 'detailLink': order.detail_link}
- )
- @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"获取服务异常"))
- @permission_required(ROLE.myuser)
- def getUserBalanceCharge(request):
- user = request.user
- pageIndex = int(request.GET.get("pageIndex", 1))
- pageSize = int(request.GET.get("pageSize", 10))
- logs = UserBalanceLog.get_logs(user, pageIndex=pageIndex, pageSize=pageSize)
- dataList = [_.to_dict() for _ in logs.order_by("-id")]
- return JsonOkResponse(payload={
- "total": get_paginate(dataList, pageSize=pageSize, pageIndex=pageIndex),
- "dataList": dataList
- })
- @error_tolerate(logger=logger, nil=JsonErrorResponse(description=u"获取服务异常"))
- @permission_required(ROLE.myuser, ROLE.dealer)
- def getCardBalanceCharge(request):
- cardId = request.GET.get("cardId")
- pageIndex = int(request.GET.get("pageIndex", 1))
- pageSize = int(request.GET.get("pageSize", 10))
- card = Card.objects.filter(id=cardId).first()
- if not card:
- return JsonErrorResponse(description=u"获取服务异常 查询卡失败")
- logs = CardBalanceLog.get_logs(card, pageIndex=pageIndex, pageSize=pageSize)
- dataList = [_.to_dict() for _ in logs.order_by("-id")]
- return JsonOkResponse(payload={
- "total": get_paginate(dataList, pageSize=pageSize, pageIndex=pageIndex),
- "dataList": dataList
- })
|