123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import base64
- import copy
- import datetime
- import hashlib
- import hmac
- import json
- import logging
- import time
- from calendar import monthrange
- from bson.objectid import ObjectId
- from dateutil.relativedelta import relativedelta
- from django.conf import settings
- from django.utils.module_loading import import_string
- from mongoengine import DoesNotExist
- from typing import Any, Tuple, TYPE_CHECKING, Optional, Union
- from apilib.monetary import Percent, RMB, Ratio
- from apps.web.agent.models import Agent
- from apps.web.core.exceptions import InsufficientFundsError
- from apps.web.dealer.constant import TodoTypeEnum, TodoDone
- from apps.web.dealer.define import DEALER_INCOME_SOURCE, DEALER_INCOME_TYPE
- from apps.web.dealer.models import DealerRechargeRecord, ItemType, Dealer, VirtualCard, TodoMessage
- from apps.web.device.models import Group, Device, StockRecord
- from apps.web.management.models import Manager
- from apps.web.utils import DealerLoginPageResponseRedirect, DealerMainPageResponseRedirect, \
- SubAccountLoginResponseRedirect, concat_front_end_url
- if TYPE_CHECKING:
- from library.memcache_backend import CustomizedMemcachedCacheBackend
- from apps.web.core.payment import WechatPaymentGateway
- from apps.web.device.models import DeviceRentOrder
- logger = logging.getLogger(__name__)
- def gen_login_response(agentId):
- response = DealerLoginPageResponseRedirect(register = True)
- if agentId:
- agent = Agent.objects(id = str(agentId)).get()
- if agent.featureToggles.has_key('forbiddenDealerRegister') and agent.featureToggles['forbiddenDealerRegister']:
- response = DealerLoginPageResponseRedirect(register = False)
- if agent.is_primary:
- response.set_cookie(key = 'dealer_login_agentid', value = '', max_age = 0,
- expires = 'Thu, 01-Jan-1970 00:00:00 GMT', domain = settings.COOKIE_DOMAIN)
- response.set_cookie(key = 'dealer_login_agentid', value = '', max_age = 0,
- expires = 'Thu, 01-Jan-1970 00:00:00 GMT')
- response.set_cookie(key = 'dealer_login_managerid', value = agent.managerId,
- max_age = 24 * 3600 * 30, domain = settings.COOKIE_DOMAIN)
- else:
- response.set_cookie(key = 'dealer_login_managerid', value = '', max_age = 0,
- expires = 'Thu, 01-Jan-1970 00:00:00 GMT', domain = settings.COOKIE_DOMAIN)
- response.set_cookie(key = 'dealer_login_managerid', value = '', max_age = 0,
- expires = 'Thu, 01-Jan-1970 00:00:00 GMT')
- response.set_cookie(key = 'dealer_login_agentid', value = str(agent.id),
- max_age = 24 * 3600 * 30, domain = settings.COOKIE_DOMAIN)
- response = agent.put_cookie(response)
- return response
- def gen_subaccount_login_response(agentId):
- response = SubAccountLoginResponseRedirect(agentId)
- if agentId:
- response.set_cookie(key = 'dealer_login_agentid', value = str(agentId),
- max_age = 24 * 3600 * 30, domain = settings.COOKIE_DOMAIN)
- return response
- def gen_home_response(agentId):
- response = DealerMainPageResponseRedirect()
- response = Agent.record_cookie(agentId, response)
- return response
- INCOME_SOURCE_ALIASES = {
- DEALER_INCOME_SOURCE.RECHARGE: 'apps.web.common.proxy.ClientRechargeModelProxy',
- DEALER_INCOME_SOURCE.RECHARGE_CARD: 'apps.web.common.proxy.ClientRechargeModelProxy',
- DEALER_INCOME_SOURCE.RECHARGE_VIRTUAL_CARD: 'apps.web.common.proxy.ClientRechargeModelProxy',
- DEALER_INCOME_SOURCE.INSURANCE: 'apps.web.common.proxy.ClientRechargeModelProxy',
- DEALER_INCOME_SOURCE.AD: 'apps.web.ad.models.AdRecord',
- DEALER_INCOME_SOURCE.REDPACK: 'apps.web.common.proxy.ClientRechargeModelProxy',
- DEALER_INCOME_SOURCE.AUTO_SIM: 'apps.web.common.proxy.ClientRechargeModelProxy',
- DEALER_INCOME_SOURCE.REFUND_CASH: 'apps.web.common.proxy.ClientRechargeModelProxy'
- }
- _income_source = {}
- def resolve_income_source(channel = None):
- try:
- channel = INCOME_SOURCE_ALIASES[channel]
- except KeyError:
- if '.' not in channel and ':' not in channel:
- from kombu.utils.text import fmatch_best
- alt = fmatch_best(channel, INCOME_SOURCE_ALIASES)
- if alt:
- raise KeyError(
- 'No such income channel: {0}. Did you mean {1}?'.format(
- channel, alt))
- raise KeyError('No such transport: {0}'.format(channel))
- return import_string(channel)
- def get_income_source_cls(transport = None):
- # type: (str)->Any
- if transport not in _income_source:
- _income_source[transport] = resolve_income_source(transport)
- return _income_source[transport]
- # keys
- DEALER_DAILY_INCOME_CACHE_KEY = 'd-income:{dealerId}:source:{source}:date:{year:d}-{month:d}-{day:d}'
- DEALER_MONTHLY_INCOME_CACHE_KEY = 'd-income:{dealerId}:source:{source}:date:{year:d}-{month:d}'
- DEALER_CONSUMPTION_CACHE_KEY = 'd-consumption:{dealerId}:source:{source}:date:{date}'
- def dealer_daily_income_cache_key(dealerId, source, year, month, day):
- # type: (ObjectId, str, int, int, int)->str
- """
- :param dealerId:
- :param source:
- :param year:
- :param month:
- :param day:
- :return:
- """
- return DEALER_DAILY_INCOME_CACHE_KEY.format(dealerId = str(dealerId), source = str(source), year = year,
- month = month, day = day)
- def dealer_monthly_income_cache_key(dealerId, source, year, month):
- """
- :param dealerId:
- :param source:
- :param year:
- :param month:
- :return:
- """
- return DEALER_MONTHLY_INCOME_CACHE_KEY.format(dealerId = str(dealerId), source = str(source), year = year,
- month = month)
- def get_month_range(year, month):
- # type: (int, int)->Tuple[str, str]
- """
- :param year:
- :param month:
- :return:
- """
- DATE_FMT_TEXT = '{year}-{month}-{day}'
- _, end = monthrange(year = int(year), month = int(month))
- return (
- # start
- DATE_FMT_TEXT.format(year = year, month = month, day = 1),
- # end
- DATE_FMT_TEXT.format(year = year, month = month, day = end)
- )
- def dealer_consumption_cache_key(dealerId, source, date):
- # type: (ObjectId, str, str)->str
- """
- :param dealerId:
- :param source:
- :param date:
- :return:
- """
- return DEALER_CONSUMPTION_CACHE_KEY.format(dealerId = str(dealerId), source = str(source), date = str(date))
- def get_devices_count_by_owner(cache, ownerId):
- # type: (CustomizedMemcachedCacheBackend, str)->Tuple[int, int, int]
- """
- :param ownerId:
- :return:
- """
- def get_devices_by_dealer(dealer):
- # type:(Dealer)->list
- groupIds = Group.get_group_ids_of_dealer_and_partner(str(dealer.id))
- devices = Device.get_devices_by_group(groupIds, verbose = True)
- return devices.values()
- def is_pure_partner(agentId):
- # type:(str)->bool
- agent = Agent.objects(id = agentId).get() # type: Agent
- manager = Manager.objects(id = agent.managerId).get() # type: Manager
- isPurePartner = manager.supports('partners_are_pure')
- return isPurePartner
- def create_partner(username, password, agentId, nickname, annualTrafficCost, agentProfitShare):
- # type:(str, str, str, str, Percent)->Dealer
- """
- :param username:
- :param password:
- :param agentId:
- :param nickname:
- :param agentProfitShare:
- :return:
- """
- return Dealer.create_user(username = username,
- password = password,
- agentId = agentId,
- nickname = nickname,
- adShow = True,
- noAdPolicy = 'banner',
- annualTrafficCost = annualTrafficCost,
- agentProfitShare = agentProfitShare,
- isPurePartner = is_pure_partner(agentId))
- def update_partner(dealerId, agentId, **kwargs):
- """
- :param dealerId:
- :param agentId:
- :param kwargs:
- :return:
- """
- return Dealer.update_dealer(dealerId, isPurePartner = is_pure_partner(agentId), **kwargs)
- def consume_stock(devObj, consumeCount, detail = ''):
- countAll = 0
- devNo = devObj.devNo
- consumptionQuantity = getattr(devObj, 'consumptionQuantity', 0)
- consumptionQuantity += consumeCount
- for k, v in devObj.stockDetailDict.items(): # 兑币机实际只有一个品类,硬币
- if v >= consumeCount:
- v = v - consumeCount
- else:
- return False
- devObj.stockDetailDict[k] = v
- countAll += v
- try:
- itemObj = ItemType.objects.get(id = k)
- except Exception, e:
- logger.info('get itemtype error=%s' % e)
- return False
- more = '%s' % itemObj.title if not detail else '%s(%s)' % (itemObj.title, detail)
- if len(devObj.stockDetailDict) == 0: # 要考虑兑币机这种没有品类的设备
- countAll = getattr(devObj, 'quantity') - consumeCount
- more = u'出币'
- try:
- devObj.save()
- except Exception, e:
- logger.info('save obj error,devNo=%s' % devNo)
- return False
- result = Device.update_field(dev_no = devNo, update = True, quantity = countAll,
- consumptionQuantity = consumptionQuantity)
- if not result:
- logger.info('update field failed,devNo=%s' % devNo)
- return False
- stockTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
- StockRecord.get_collection().insert(
- {'logicCode': devObj.logicalCode, 'imei': devNo, 'stockType': 'consume', 'stockTime': stockTime,
- 'number': consumeCount, 'more': more})
- return True
- # 经销商创建虚拟卡(线下)
- class VirtualCardBuilder(object):
- """
- #创建虚拟卡空卡可以指定数量
- """
- @staticmethod
- def create_virtual_card(dealer, vCard, attachParas = {}, accounting = False):
- """
- 创建虚拟卡号,此卡的
- """
- from apps.web.user.models import UserVirtualCard
- num = attachParas.get('number')
- cardId = attachParas.get('card_id')
- lis = []
- for i in xrange(int(num)):
- user_card = UserVirtualCard(
- cardNo = UserVirtualCard.make_no(),
- cardTypeId = str(cardId),
- openIds = [],
- cardName = vCard.cardName,
- ownerOpenId = vCard.ownerId,
- # nickname=dealer.nickname,
- dealerId = vCard.ownerId,
- groupIds = vCard.groupIds,
- devTypeList = vCard.devTypeList,
- price = vCard.price,
- periodDays = vCard.periodDays,
- expiredTime = datetime.datetime.now() + datetime.timedelta(seconds = vCard.periodDays * 24 * 3600),
- startTime = datetime.datetime.now(),
- dayQuota = vCard.dayQuota,
- userLimit = 1,
- quota = vCard.quota,
- # userDesc=vCard.userDesc,
- remark = '经销商开卡',
- status = 'nonactivated'
- )
- user_card.nickname = user_card.cardNo
- user_card.save()
- lis.append(user_card.cardNo)
- return lis
- @staticmethod
- def find_dealer_virtual_card(dealerId, status = 'nonactivated'):
- """
- #查询经销商开的空卡
- :param dealerId:
- :param status:
- :return:
- """
- from apps.web.user.models import UserVirtualCard
- virtual_cards = UserVirtualCard.objects.filter(ownerOpenId = dealerId, dealerId = dealerId, status = status)
- return virtual_cards
- @staticmethod
- def active_virtual_card(VirtualCardId):
- """
- 经销商给实体卡绑定后激活卡片
- :param VirtualCardId:
- :return:
- """
- result = False
- from apps.web.user.models import UserVirtualCard
- try:
- virtual_card = UserVirtualCard.objects.get(id = VirtualCardId)
- card_model = VirtualCard.objects.get(id = virtual_card.cardTypeId)
- except Exception as e:
- logger.info('VirtualCardBuilder_no this virtual_card cardNo:%s' % VirtualCardId)
- return result
- virtual_card.startTime = datetime.datetime.now
- virtual_card.expiredTime = datetime.datetime.now() + datetime.timedelta(
- seconds = card_model.periodDays * 24 * 3600)
- virtual_card.status = 'normal'
- virtual_card.save()
- return True
- @staticmethod
- def unbind_virtual_card(card):
- """
- 解绑虚拟卡,并改变虚拟卡状态
- :param card:
- :return:
- """
- result = False
- try:
- virtual_card = card.bound_virtual_card
- if datetime.datetime.now() > virtual_card.expiredTime:
- virtual_card.status = 'expired'
- else:
- virtual_card.status = 'used'
- virtual_card.save()
- card.boundVirtualCardId = None
- card.save()
- result = True
- except Exception as e:
- logger.error('card:{},error={}'.format(card.cardNo, e))
- pass
- return result
- def create_dealer_sim_charge_order(payment_gateway, dealer, devItems, payType = "pay", can_used_balance = None):
- from apps.web.common.transaction import DealerPaySubType
- from apps.web.core import ROLE
- sub_type = DealerPaySubType.SIM_CARD
- if payType == 'auto':
- sub_type = DealerPaySubType.AUTO_SIM_CARD
- elif payType == 'manual':
- sub_type = DealerPaySubType.MANUAL_SIM_CARD
- subServiceName = DealerRechargeRecord.get_product(sub_type)['desc']
- dealerId = dealer.bossId
- curr_annualTrafficCost = dealer.annualTrafficCost
- total_fee = int(0)
- total_agent_earning_fee = int(0)
- total_manager_earning_fee = int(0)
- agent = Agent.objects(id = dealer.agentId).first() # type: Optional[Agent]
- if not agent:
- logger.error('agent<id={}> is not exist.'.format(dealer.agentId))
- return None
- # 代理商的成本价. 代理商给经销商设置流量卡费用必须大于等于这个价格
- agentAnnualTrafficCost = agent.annualTrafficCost
- agentAnnualTrafficCostFen = int((agentAnnualTrafficCost * 100))
- primeAgent = agent.primary_agent
- name = u'%s 设备号' % subServiceName
- items = []
- devNo = None
- for item in devItems:
- if isinstance(item, Device):
- dev = item
- else:
- dev = Device.get_dev(item)
- if not dev:
- logger.error('{} is not exist.'.format(item))
- continue
- devNo = dev.devNo
- name = '%s %s' % (name, dev.logicalCode)
- dev_obj = Device.objects.get(devNo = devNo)
- trafficCardCost = dev_obj.trafficCardCost
- if not trafficCardCost:
- trafficCardCost = getattr(dealer, 'trafficCardCost', None)
- if not trafficCardCost:
- trafficCardCost = agent.trafficCardCost
- platform_cost_fen = RMB.yuan_to_fen(trafficCardCost)
- if trafficCardCost > curr_annualTrafficCost:
- annualTrafficCost = trafficCardCost
- else:
- annualTrafficCost = curr_annualTrafficCost
- annualTrafficCostFen = RMB.yuan_to_fen(annualTrafficCost)
- total_fee += annualTrafficCostFen
- group = Group.get_group(dev['groupId'])
- # 可以分给代理商和厂商的钱
- total_earn_fee = annualTrafficCostFen - platform_cost_fen
- # 分给代理商的钱 = 经销商充值费用 - 厂商给代理商配置的成本价格. 如果该值小于0就不分
- # 如果该值大于total_earn, 就把total_earn全部分给他
- agent_earning_fee = (annualTrafficCostFen - agentAnnualTrafficCostFen) \
- if (annualTrafficCostFen - agentAnnualTrafficCostFen) > 0 else 0
- if agent_earning_fee > total_earn_fee:
- agent_earning_fee = total_earn_fee
- manager_earning_fee = total_earn_fee - agent_earning_fee
- total_agent_earning_fee += agent_earning_fee
- total_manager_earning_fee += manager_earning_fee
- item_payload = {
- 'name': u'%s %s %s %s' % (dev['devType']['name'], dev['logicalCode'], group['address'], subServiceName),
- 'devNo': devNo,
- 'iccid': dev.iccid,
- 'price': str(annualTrafficCost.amount),
- 'dealerPrice': str(curr_annualTrafficCost.amount),
- 'cost': str(trafficCardCost.amount),
- 'currCost': str(agent.trafficCardCost.amount),
- 'agentCost': str(agentAnnualTrafficCost.amount),
- 'number': 1,
- 'partition': [
- {
- 'role': ROLE.agent,
- 'id': str(agent.id),
- 'earned': agent_earning_fee
- },
- {
- 'role': ROLE.manager,
- 'id': str(primeAgent.id),
- 'earned': manager_earning_fee
- }
- ]}
- items.append(item_payload)
- payload = {
- 'items': items,
- 'name': name,
- 'dealerId': str(dealerId),
- 'nickname': dealer.nickname,
- 'totalFee': 0 if payType == 'manual' else total_fee,
- 'settleInfo': {
- },
- 'wxOrderNo': '',
- 'attachParas': {}
- }
- if str(agent.id) == str(primeAgent.id):
- payload['settleInfo']['partition'] = [
- {
- 'id': str(agent.id),
- 'earned': total_agent_earning_fee + total_manager_earning_fee
- }
- ]
- else:
- payload['settleInfo']['partition'] = [
- {
- 'id': str(agent.id),
- 'earned': total_agent_earning_fee
- },
- {
- 'id': str(primeAgent.id),
- 'earned': total_manager_earning_fee
- }
- ]
- if payType == 'auto':
- costMoney = RMB(total_fee / 100.0)
- if costMoney > can_used_balance:
- raise InsufficientFundsError()
- record = DealerRechargeRecord.issue(
- sub_type, payment_gateway, dealer, devNo, **payload)
- if record:
- return record
- return None
- def create_dealer_sim_charge_verify_order(dealer, partitions, recharge_order):
- from apps.web.common.transaction import DealerPaySubType
- total_fee = 0
- for partition in partitions:
- total_fee += partition['earned']
- from apps.web.helpers import get_platform_reconcile_pay_gateway
- payment_gateway = get_platform_reconcile_pay_gateway()
- sub_type = DealerPaySubType.SIM_ORDER_VERIFY
- payload = {
- 'items': None,
- 'name': DealerRechargeRecord.get_product(sub_type)['desc'],
- 'dealerId': str(dealer.id),
- 'nickname': dealer.nickname,
- 'totalFee': total_fee,
- 'settleInfo': {'partition': partitions},
- 'wxOrderNo': '',
- 'attachParas': {'rechargeId': str(recharge_order.id)}
- }
- record = DealerRechargeRecord.issue(sub_type, payment_gateway, dealer, **payload)
- if record:
- return record
- return None
- def create_dealer_charge_order_for_api(dealer, **kw):
- from apps.web.common.transaction import DealerPaySubType
- from apps.web.core import ROLE
- from apps.web.helpers import get_inhourse_wechat_env_pay_gateway
- apiDevicePerCost = dealer.api_app.apiDevicePerCost # type: RMB # 单价
- subServiceName = DealerRechargeRecord.get_product(DealerPaySubType.API_COST)['desc']
- dealerId = dealer.bossId
- name = u'%s' % subServiceName
- dev_count = kw.get('needQuota', 0)
- total_yuan = apiDevicePerCost * Ratio(dev_count)
- total_fee = RMB.yuan_to_fen(total_yuan)
- payment_gateway = get_inhourse_wechat_env_pay_gateway(
- ROLE.dealer) # type: Union[WechatPaymentGateway]
- agent = payment_gateway.occupant
- items = [
- kw
- ]
- payload = {
- 'items': items,
- 'name': name,
- 'dealerId': str(dealerId),
- 'nickname': dealer.nickname,
- 'totalFee': total_fee,
- 'settleInfo': {
- 'partition': [
- {
- 'id': str(agent.id),
- 'earned': total_fee
- }
- ]
- },
- 'wxOrderNo': '',
- 'attachParas': {}
- }
- record = DealerRechargeRecord.issue(DealerPaySubType.API_COST,
- payment_gateway,
- dealer,
- **payload)
- if record:
- return record
- return None
- def create_dealer_charge_order_for_disable_ad(dealer, devList):
- from apps.web.common.transaction import DealerPaySubType
- from apps.web.core import ROLE
- from apps.web.helpers import get_inhourse_wechat_env_pay_gateway
- disableAdCost = dealer.disable_ad_plan.disableAdCost # type: RMB # 单价
- cycle = dealer.disable_ad_plan.cycle # type: RMB # 事件周期
- subServiceName = DealerRechargeRecord.get_product(DealerPaySubType.DISABLE_AD)['desc']
- dealerId = dealer.bossId
- payment_gateway = get_inhourse_wechat_env_pay_gateway(
- ROLE.dealer) # type: Union[WechatPaymentGateway]
- agent = payment_gateway.occupant
- dev_count = len(devList)
- name = u'添加%s(%s台)' % (subServiceName, dev_count)
- total_yuan = disableAdCost * Ratio(dev_count)
- total_fee = RMB.yuan_to_fen(total_yuan)
- payload = {
- 'items': devList,
- 'name': name,
- 'dealerId': str(dealerId),
- 'nickname': dealer.nickname,
- 'totalFee': total_fee,
- 'settleInfo': {
- 'partition': [
- {
- 'id': str(agent.id),
- 'earned': total_fee
- }
- ]
- },
- 'wxOrderNo': '',
- 'attachParas': {}
- }
- record = DealerRechargeRecord.issue(DealerPaySubType.DISABLE_AD,
- payment_gateway,
- dealer,
- **payload)
- if record:
- return record
- return None
- class DealerSessionBuilder(object):
- OPER_ID = 'oper_id'
- MASTER_ID = '_auth_user_id'
- def __init__(self, request = None):
- self.request = request
- def is_dealer_trustee(self):
- if self.request.session.get(self.OPER_ID):
- return True
- else:
- return False
- def check_out_to_dealer_trustee(self, oper_id):
- self.request.session[self.OPER_ID] = oper_id
- self.request.session.save()
- def check_out_to_dealer_master(self):
- # 校验master_id
- master_id = self.request.session.get(self.MASTER_ID)
- dealer = Dealer.objects.filter(id = master_id).first()
- subAccouny = Dealer.objects.filter(id = master_id).first()
- if not subAccouny and dealer:
- self.request.session.clear()
- return False
- else:
- # 切换
- self.request.session.pop(self.OPER_ID, None)
- self.request.session.save()
- return True
- class MyToken(object):
- KEY = 'c4NEwO'
- @staticmethod
- def b64encode(j_s):
- return base64.urlsafe_b64encode(j_s).replace(b'=', b'')
- @staticmethod
- def b64decode(b_s):
- # 补全签发时替换掉的等号,找规律:肯定能被4整除,替换掉的‘=’个数是:4 - 总长 % 4
- rem = len(b_s) % 4
- if rem > 0:
- b_s += b'=' * (4 - rem)
- return base64.urlsafe_b64decode(str(b_s))
- @staticmethod
- def encode(payload, key = KEY, exp = 60 * 15):
- header = {'typ': 'JWT', 'alg': 'HS256'}
- header_json = json.dumps(header, sort_keys = True, separators = (',', ':'))
- header_bs = MyToken.b64encode(header_json.encode())
- my_payload = copy.deepcopy(payload)
- my_payload['exp'] = time.time() + int(exp)
- payload_json = json.dumps(my_payload, sort_keys = True, separators = (',', ':'))
- payload_bs = MyToken.b64encode(payload_json.encode())
- if isinstance(key, str):
- key = key.encode()
- hm = hmac.new(key, header_bs + b'.' + payload_bs, digestmod = hashlib.sha256)
- hm_bs = MyToken.b64encode(hm.digest())
- return header_bs + b'.' + payload_bs + b'.' + hm_bs
- @staticmethod
- def decode(jwt_s, key = KEY):
- header_bs, payload_bs, sign_bs = jwt_s.split(b'.')
- if isinstance(key, str):
- key = key.encode()
- hm = hmac.new(key, header_bs + b'.' + payload_bs, digestmod = hashlib.sha256)
- new_sign_bs = MyToken.b64encode(hm.digest())
- if new_sign_bs != sign_bs:
- raise
- payload_json = MyToken.b64decode(payload_bs)
- payload = json.loads(payload_json)
- exp = payload['exp']
- now_t = time.time()
- if now_t > exp:
- raise
- return payload
- class RentOrderServer(object):
- def __init__(self, order, dealer=None): # type:(DeviceRentOrder, Optional[Dealer, None]) -> None
- self.order = order
- self.dealer = dealer or order.dealer
- def execute(self):
- """
- 执行订单的扣款
- :return:
- """
- logger.info("device rent order <{}> start execute!".format(self.order.id))
- # 几个常量 扣款目前只从设备收益中进行扣除
- incomeType = DEALER_INCOME_TYPE.DEVICE_INCOME
- exTime = datetime.datetime.now()
- balanceList = self.dealer.__class__.get_income_balance_list(self.dealer, incomeType)
- for _sourceKey, _balance in balanceList:
- # 金额不足的情况下继续
- if RMB(_balance) < RMB(self.order.billAmount):
- continue
- # 对订单金额进行冻结
- update = self.dealer.rent_freeze_balance(
- incomeType,
- self.order.billAmount,
- _sourceKey,
- str(self.order.id)
- )
- if not update:
- logger.info("device rent order <{}> execute freeze error!".format(self.order.id))
- self.order.update_for_fail(exTime, reason=u"扣款失败")
- return False
- # 扣款成功的情况下
- try:
- self.order.update_for_success(exTime, _sourceKey)
- except Exception as e:
- logger.exception("device rent order <{}> execute update success error = {}!".format(self.order.id, e))
- self.dealer.rent_recover_frozen_balance(
- incomeType,
- self.order.billAmount,
- _sourceKey,
- str(self.order.id)
- )
- return False
- # 执行成功
- self.dealer.rent_clear_frozen_balance(str(self.order.id))
- logger.info("device rent order <{}> execute success!".format(self.order.id))
- return True
- else:
- self.order.update_for_fail(exTime, u"余额不足")
- # 整个余额都不足够
- logger.info("device rent order <{}> dealer <{}> balance not enough".format(self.order.id, self.dealer.id))
- return False
- class TodoProcessor(object):
- @classmethod
- def insert_todo(cls, user):
- pass
- @classmethod
- def check_has_done(cls, todo):
- return False, False
|