12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import base64
- import datetime
- import hashlib
- import logging
- import os
- from importlib import import_module
- import simplejson as json
- from django.conf import settings
- from django.core.cache import cache
- from django.utils.functional import cached_property
- from django.utils.module_loading import import_string
- from mongoengine import StringField, DateTimeField, EmbeddedDocument, DictField, BooleanField, DynamicField, ListField, \
- IntField, LazyReferenceField, ObjectIdField, DynamicDocument, EmbeddedDocumentField, GenericLazyReferenceField
- from typing import List, cast, TYPE_CHECKING
- from apilib.monetary import RMB
- from apilib.systypes import IterConstant
- from apilib.utils import flatten
- from apilib.utils_json import json_loads, json_dumps
- from apilib.utils_string import encrypt_display
- from apilib.utils_sys import ThreadLock
- from apps import serviceCache
- from apps.web.common.transaction import OrderNoMaker, OrderMainType, OtherOrderSubType
- from apps.web.constant import Const, PARTITION_ROLE
- from apps.web.core import PayAppType, APP_KEY_DELIMITER, ROLE
- from apps.web.core.db import Searchable
- from apps.web.exceptions import UserServerException
- from library.alipay import AliException, AliPay, DCAliPay
- from library.wechatpayv3 import update_certificates
- logger = logging.getLogger(__name__)
- if TYPE_CHECKING:
- from apps.web.dealer.models import Dealer
- class FAQ(Searchable):
- """
- 配置FAQ,首先让经销商|终端用户看到常用问题,找不到问题再联系客服
- """
- question = StringField(verbose_name = '问题')
- answer = StringField(verbose_name = '答案')
- target = StringField(verbose_name = '目标 := (Dealer|Agent|EndUser)', default = '*')
- devTypeId = StringField(verbose_name = '设备类型ID,默认为普适性问题,为空', default = '')
- images = ListField(verbose_name = '辅助说明图像')
- videos = ListField(verbose_name = '辅助说明视频')
- upvotes = IntField(verbose_name = '该FAQ有帮助')
- downvotes = IntField(verbose_name = '该FAQ没有帮助')
- meta = {'collection': 'faqs', 'db_alias': 'default'}
- def to_dict(self):
- return {
- 'id': str(self.id),
- 'question': self.question,
- 'answer': self.answer,
- 'target': self.target,
- 'images': self.images,
- 'videos': self.videos,
- 'devTypeId': self.devTypeId,
- 'upvotes': self.upvotes,
- 'downvotes': self.downvotes
- }
- @classmethod
- def get_by_target(cls, target):
- return cls.objects(target__in = ['*', target])
- class EmbeddedApp(EmbeddedDocument):
- meta = {
- 'abstract': True
- }
- appid = StringField(verbose_name = 'appid', default = '')
- secret = StringField(verbose_name = "secretId", default = '', max_length = 32)
- name = StringField(verbose_name = "name", default = '')
- companyName = StringField(verbose_name = "companyName", default = '')
- @property
- def debug(self):
- return False
- @property
- def occupantId(self):
- return getattr(self, '__occupant_id__', '')
- @occupantId.setter
- def occupantId(self, occupant_id):
- self.__occupant_id__ = occupant_id
- @property
- def occupant(self):
- return getattr(self, '__occupant__', None)
- @occupant.setter
- def occupant(self, occupant):
- self.__occupant__ = occupant
- @property
- def __valid_check__(self):
- return bool(self.appid and self.secret)
- @property
- def valid(self):
- if hasattr(self, '__valid__'):
- return getattr(self, '__valid__')
- else:
- if not hasattr(self, '__valid_check__'):
- raise AttributeError('no __valid_check__ attribute')
- else:
- return getattr(self, '__valid_check__')
- @valid.setter
- def valid(self, value):
- self.__valid__ = value
- @property
- def enable(self):
- return getattr(self, '__enable__', True)
- @enable.setter
- def enable(self, is_enable):
- self.__enable__ = is_enable
- @classmethod
- def get_null_app(cls):
- app = cls(appid = '', secret = '')
- app.enable = False
- app.valid = True
- return app
- @staticmethod
- def from_json_string(app_string):
- app_dict = json.loads(app_string)
- _model = app_dict.pop('model')
- _cls = import_string(_model)
- return _cls(**app_dict)
- class WechatAuthApp(EmbeddedApp):
- def __repr__(self): return '<WechatAuthApp appid=%s>' % (self.appid,)
- def to_dict(self):
- return {
- 'appid': self.appid,
- 'secret': self.secret,
- 'name': self.name,
- 'companyName': self.companyName
- }
- @property
- def client(self):
- if hasattr(self, '__client__'):
- return getattr(self, '__client__')
- class WechatManagerApp(EmbeddedApp):
- templateIdMap = DictField(verbose_name = u"微信推送消息模版ID字典", default = {})
- MESSAGE_TEMPLATE = {
- 'feedback': {
- 'templateId': '',
- 'context': json.dumps({
- "first": {
- "value": u'${title}',
- "color": "#173177"
- },
- "keyword1": {
- "value": u'${nickname}',
- "color": "#173177"
- },
- "keyword2": {
- "value": '${feedbackTime}',
- "color": "#173177"
- },
- "remark": {
- "value": "客户就是上帝,请及时处理!",
- "color": "#173177"
- }
- })
- },
- 'daily_income': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- "value": '${reportTime}',
- "color": '#173177'
- },
- 'keyword2': {
- 'value': u'${report}',
- 'color': '#173177'
- },
- 'remark': {
- 'value': u'祝您今日工作愉快!',
- 'color': '#173177'
- }
- })
- },
- 'new_payment_order': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- 'value': u'${customer}',
- 'color': '#173177'
- },
- 'keyword2': {
- 'value': u'${income}',
- 'color': '#173177'
- },
- 'remark': {
- 'value': u'祝您生意兴隆!',
- 'color': '#173177'
- }
- })
- },
- 'abnormal_device_offline': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- "value": u'${device}',
- "color": '#173177'
- },
- 'keyword2': {
- 'value': '${notifyTime}',
- 'color': '#173177'
- },
- 'remark': {
- 'value': u'感谢您的使用,小客服随时为您服务',
- 'color': '#173177'
- }
- })
- },
- 'device_fault': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- "value": u'${device}',
- "color": '#173177'
- },
- 'keyword2': {
- 'value': u'${location}',
- 'color': '#173177'
- },
- 'keyword3': {
- 'value': u'${fault}',
- 'color': '#173177'
- },
- 'keyword4': {
- 'value': '${notifyTime}',
- 'color': '#173177'
- },
- 'remark': {
- 'value': u'感谢您的使用,小客服随时为您服务',
- 'color': '#173177'
- }
- })
- },
- 'sim_expire_notify': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- "value": u'${num}',
- "color": '#173177'
- },
- 'keyword2': {
- 'value': u'${type}',
- 'color': '#173177'
- },
- 'keyword3': {
- 'value': u'${time}',
- 'color': '#173177'
- },
- 'remark': {
- 'value': u'感谢您一直以来对我们工作的支持与帮助',
- 'color': '#173177'
- }
- })
- },
- 'system_alarm_notify': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- "value": u'${account}',
- "color": '#173177'
- },
- 'keyword2': {
- 'value': u'${object}',
- 'color': '#173177'
- },
- 'keyword3': {
- 'value': u'${content}',
- 'color': '#173177'
- },
- 'keyword4': {
- 'value': u'${time}',
- 'color': '#173177'
- },
- 'remark': {
- 'value': u'客户就是上帝,请尽快处理',
- 'color': '#173177'
- }
- })
- },
- # 'online_notify': {
- # 'templateId': '',
- # 'context': json.dumps({
- # 'first': {
- # 'value': u'设备正常上线',
- # 'color': '#173177'
- # },
- # 'keyword1': {
- # "value": u'正常上线',
- # "color": '#173177'
- # },
- # 'keyword2': {
- # 'value': u'${device}',
- # 'color': '#173177'
- # },
- # 'keyword3': {
- # 'value': '${devNo}',
- # 'color': '#173177'
- # },
- # 'keyword4': {
- # 'value': '${devType}',
- # 'color': '#173177'
- # },
- # 'keyword5': {
- # 'value': '${address}',
- # 'color': '#173177'
- # },
- # 'remark': {
- # 'value': u'感谢您的使用,小客服随时为您服务',
- # 'color': '#173177'
- # }
- # })
- # }
- }
- def __repr__(self):
- return '<{class_name} appid={appid}>'.format(class_name = self.__class__.__name__, appid = self.appid)
- def to_dict(self):
- template_id_map = []
- for templateName, template in self.templateIdMap.iteritems():
- template_id_map.append({
- 'key': templateName,
- 'name': Const.TRANSLATION[templateName] if templateName in Const.TRANSLATION else templateName,
- 'value': template['templateId']
- })
- for templateName, message_tmpl in self.MESSAGE_TEMPLATE.iteritems():
- if templateName not in self.templateIdMap.keys():
- template_id_map.append({
- 'key': templateName,
- 'name': Const.TRANSLATION[templateName] if templateName in Const.TRANSLATION else templateName,
- 'value': ''
- })
- return {
- 'appid': self.appid,
- 'secret': self.secret,
- 'name': self.name,
- 'companyName': self.companyName,
- 'templateIdMap': template_id_map
- }
- @classmethod
- def create(cls, appid, secret, templateIdMap = None, name = '', companyName = ''):
- __template_id_map = {}
- if templateIdMap:
- for item in templateIdMap:
- if item['key'] not in cls.MESSAGE_TEMPLATE:
- continue
- __template_id_map[item['key']] = {
- 'templateId': item['value'].strip() if item['value'] else '',
- 'context': cls.MESSAGE_TEMPLATE[item['key']]['context']
- }
- else:
- __template_id_map.update(cls.MESSAGE_TEMPLATE)
- return cls(appid = appid, secret = secret, templateIdMap = __template_id_map, name = name,
- companyName = companyName)
- class WechatUserManagerApp(EmbeddedApp):
- templateIdMap = DictField(verbose_name = u"微信推送消息模版ID字典", default = {})
- MESSAGE_TEMPLATE = {
- 'feedback_process': {
- 'templateId': '',
- 'context': json.dumps({
- "first": {
- "value": u"${title}",
- "color": "#173177"
- },
- "event": {
- "value": u"${event}",
- "color": "#173177"
- },
- "finish_time": {
- "value": '${finishTime}',
- "color": "#173177"
- },
- "remark": {
- "value": u"${remark}",
- "color": "#173177"
- }
- })
- },
- 'service_start': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- 'value': u'${service}',
- 'color': '#173177'
- },
- 'keyword2': {
- "value": u'${time}',
- "color": '#173177'
- },
- 'remark': {
- 'value': u'${remark}',
- 'color': '#173177'
- }
- })
- },
- 'service_complete': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- 'value': u'${service}',
- 'color': '#173177'
- },
- 'keyword2': {
- "value": u'${finishTime}',
- "color": '#173177'
- },
- 'remark': {
- 'value': u'${remark}',
- 'color': '#173177'
- }
- })
- },
- 'charge_order_complete': {
- 'templateId': '',
- 'context': json.dumps({
- 'keyword1': {
- 'value': u'${orderNo}',
- 'color': '#173177'
- },
- 'keyword2': {
- "value": u'${terminal}',
- "color": '#173177'
- },
- 'keyword3': {
- 'value': u'${reason}',
- 'color': '#173177'
- },
- 'keyword4': {
- 'value': u'${service}',
- 'color': '#173177'
- },
- 'keyword5': {
- 'value': u'${settle}',
- 'color': '#173177'
- }
- })
- },
- 'common_order_complete': {
- 'templateId': '',
- 'context': json.dumps({
- 'keyword1': {
- 'value': u'${orderNo}',
- 'color': '#173177'
- },
- 'keyword2': {
- "value": u'${settle}',
- "color": '#173177'
- },
- 'keyword3': {
- 'value': u'${terminal}',
- 'color': '#173177'
- },
- 'keyword4': {
- 'value': u'${startTime}',
- 'color': '#173177'
- },
- 'keyword5': {
- 'value': u'${finishTime}',
- 'color': '#173177'
- }
- })
- },
- 'refund_coins': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- 'value': u'${backCount}',
- 'color': '#173177'
- },
- 'keyword2': {
- "value": '${finishTime}',
- "color": '#173177'
- },
- 'remark': {
- 'value': u'感谢您的支持!',
- 'color': '#173177'
- }
- })
- },
- 'device_fault': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'performance': {
- "value": u'${fault}',
- "color": '#173177'
- },
- 'time': {
- 'value': u'${notifyTime}',
- 'color': '#173177'
- },
- 'remark': {
- 'value': u'感谢您的使用,小客服随时为您服务',
- 'color': '#173177'
- }
- })
- },
- 'less_balance': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- 'value': '${account}',
- 'color': '#173177'
- },
- 'keyword2': {
- "value": '${balance}',
- "color": '#173177'
- },
- 'remark': {
- 'value': u'为了不影响您的使用,建议您赶快充值!',
- 'color': '#173177'
- }
- })
- },
- 'consume_notify': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- 'value': u'${serviceType}',
- 'color': '#173177'
- },
- 'keyword2': {
- 'value': u'${money}',
- 'color': '#173177'
- },
- 'keyword3': {
- "value": '${finishTime}',
- "color": '#173177'
- },
- 'remark': {
- 'value': u'如果确认不是合法刷卡使用,可以通过解绑卡,让卡不可用。',
- 'color': '#173177'
- }
- })
- },
- 'service_expired': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- 'value': u'${department}',
- 'color': '#173177'
- },
- 'keyword2': {
- "value": '${expiredTime}',
- "color": '#173177'
- },
- 'remark': {
- 'value': u'${remark}', # u'您可以打开公众号的个人中心,选择优惠卡卷,然后选择您即将过期的卡进行续费!',
- 'color': '#173177'
- }
- })
- },
- 'dev_start': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#173177'
- },
- 'keyword1': {
- "value": u'${things}',
- "color": '#173177'
- },
- 'keyword2': {
- 'value': u'${time}',
- 'color': '#173177'
- },
- 'remark': {
- 'value': u'${remark}',
- 'color': '#173177'
- }
- })
- },
- 'insurance_sub': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#000000'
- },
- 'keyword1': {
- "value": u'${name}',
- "color": '#858585'
- },
- 'keyword2': {
- 'value': u'${category}',
- 'color': '#858585'
- },
- 'keyword3': {
- 'value': u'${orderNo}',
- 'color': '#858585'
- },
- 'keyword4': {
- 'value': u'${money}',
- 'color': '#858585'
- },
- 'keyword5': {
- 'value': u'${validTime}',
- 'color': '#858585'
- },
- 'remark': {
- 'value': u'${remark}',
- 'color': '#173177'
- }
- })
- },
- 'insurance_cancel': {
- 'templateId': '',
- 'context': json.dumps({
- 'first': {
- 'value': u'${title}',
- 'color': '#858585'
- },
- 'keyword1': {
- "value": u'${orderNo}',
- "color": '#858585'
- },
- 'keyword2': {
- 'value': u'${name}',
- 'color': '#858585'
- },
- 'keyword3': {
- 'value': u'${user}',
- 'color': '#858585'
- },
- 'keyword4': {
- 'value': u'${cancelTime}',
- 'color': '#858585'
- },
- 'keyword5': {
- 'value': u'${money}',
- 'color': '#858585'
- },
- 'remark': {
- 'value': u'${remark}',
- 'color': '#173177'
- }
- })
- },
- }
- def __repr__(self):
- return '<{class_name} appid={appid}>'.format(class_name = self.__class__.__name__, appid = self.appid)
- def to_dict(self):
- template_id_map = []
- for templateName, template in self.templateIdMap.iteritems():
- template_id_map.append({
- 'key': templateName,
- 'name': Const.TRANSLATION[templateName] if templateName in Const.TRANSLATION else templateName,
- 'value': template['templateId']
- })
- for templateName, message_tmpl in self.MESSAGE_TEMPLATE.iteritems():
- if templateName not in self.templateIdMap.keys():
- template_id_map.append({
- 'key': templateName,
- 'name': Const.TRANSLATION[templateName] if templateName in Const.TRANSLATION else templateName,
- 'value': ''
- })
- return {
- 'appid': self.appid,
- 'secret': self.secret,
- 'name': self.name,
- 'companyName': self.companyName,
- 'templateIdMap': template_id_map
- }
- @classmethod
- def create(cls, appid, secret, templateIdMap = None, name = '', companyName = ''):
- __template_id_map = {}
- if templateIdMap:
- for item in templateIdMap:
- if item['key'] not in cls.MESSAGE_TEMPLATE:
- continue
- __template_id_map[item['key']] = {
- 'templateId': item['value'].strip() if item['value'] else '',
- 'context': cls.MESSAGE_TEMPLATE[item['key']]['context']
- }
- else:
- __template_id_map.update(cls.MESSAGE_TEMPLATE)
- return cls(appid = appid, secret = secret, templateIdMap = __template_id_map, name = name,
- companyName = companyName)
- class WechatUserSubscribeManagerApp(EmbeddedApp):
- templateIdMap = DictField(verbose_name = u"微信推送消息模版ID字典", default = {})
- MESSAGE_TEMPLATE = {
- 'service_start': {
- 'templateId': '',
- 'context': json.dumps({
- 'data': {
- 'thing2': {'value': u'${service}'}, # 服务项目
- 'time4': {'value': u'${time}'}, # 开始时间
- 'thing5': {'value': u'${remark}'}, # 备注
- },
- })
- },
- 'service_complete': {
- 'templateId': '',
- 'context': json.dumps({
- 'data': {
- 'thing5': {'value': u'${service}'}, # 服务名称
- 'thing6': {'value': u'${remark}'}, # 温馨提示
- 'time3': {'value': u'${finishTime}'}, # 完成时间
- },
- })
- }
- }
- def __repr__(self):
- return '<{class_name} appid={appid}>'.format(class_name = self.__class__.__name__, appid = self.appid)
- def to_dict(self):
- template_id_map = []
- for templateName, template in self.templateIdMap.iteritems():
- template_id_map.append({
- 'key': templateName,
- 'name': Const.TRANSLATION[templateName] if templateName in Const.TRANSLATION else templateName,
- 'value': template['templateId']
- })
- for templateName, message_tmpl in self.MESSAGE_TEMPLATE.iteritems():
- if templateName not in self.templateIdMap.keys():
- template_id_map.append({
- 'key': templateName,
- 'name': Const.TRANSLATION[templateName] if templateName in Const.TRANSLATION else templateName,
- 'value': ''
- })
- return {
- 'appid': self.appid,
- 'secret': self.secret,
- 'name': self.name,
- 'companyName': self.companyName,
- 'templateIdMap': template_id_map
- }
- @classmethod
- def create(cls, appid, secret, templateIdMap = None, name = '', companyName = ''):
- __template_id_map = {}
- if templateIdMap:
- for item in templateIdMap:
- if item['key'] not in cls.MESSAGE_TEMPLATE:
- continue
- __template_id_map[item['key']] = {
- 'templateId': item['value'].strip() if item['value'] else '',
- 'context': cls.MESSAGE_TEMPLATE[item['key']]['context']
- }
- else:
- __template_id_map.update(cls.MESSAGE_TEMPLATE)
- return cls(appid = appid, secret = secret, templateIdMap = __template_id_map, name = name,
- companyName = companyName)
- class WechatDealerSubscribeManagerApp(EmbeddedApp):
- templateIdMap = DictField(verbose_name = u"微信推送消息模版ID字典", default = {})
- MESSAGE_TEMPLATE = {
- 'service_start': {
- 'templateId': '',
- 'context': json.dumps({
- 'data': {
- 'character_string1': {'value': u'${orderNo}'}, # 订单号
- 'thing2': {'value': u'${majorDeviceType}'}, # 服务项目
- 'time4': {'value': u'${time}'}, # 开始时间
- 'thing5': {'value': u'${remarks}'}, # 备注
- },
- })
- },
- }
- def __repr__(self):
- return '<{class_name} appid={appid}>'.format(class_name = self.__class__.__name__, appid = self.appid)
- def to_dict(self):
- template_id_map = []
- for templateName, template in self.templateIdMap.iteritems():
- template_id_map.append({
- 'key': templateName,
- 'name': Const.TRANSLATION[templateName] if templateName in Const.TRANSLATION else templateName,
- 'value': template['templateId']
- })
- for templateName, message_tmpl in self.MESSAGE_TEMPLATE.iteritems():
- if templateName not in self.templateIdMap.keys():
- template_id_map.append({
- 'key': templateName,
- 'name': Const.TRANSLATION[templateName] if templateName in Const.TRANSLATION else templateName,
- 'value': ''
- })
- return {
- 'appid': self.appid,
- 'secret': self.secret,
- 'name': self.name,
- 'companyName': self.companyName,
- 'templateIdMap': template_id_map
- }
- @classmethod
- def create(cls, appid, secret, templateIdMap = None, name = '', companyName = ''):
- __template_id_map = {}
- if templateIdMap:
- for item in templateIdMap:
- if item['key'] not in cls.MESSAGE_TEMPLATE:
- continue
- __template_id_map[item['key']] = {
- 'templateId': item['value'].strip() if item['value'] else '',
- 'context': cls.MESSAGE_TEMPLATE[item['key']]['context']
- }
- else:
- __template_id_map.update(cls.MESSAGE_TEMPLATE)
- return cls(appid = appid, secret = secret, templateIdMap = __template_id_map, name = name,
- companyName = companyName)
- def get_sub_template_id_list(self):
- if not self.templateIdMap:
- return []
- else:
- try:
- return map(lambda _: _['templateId'], self.templateIdMap.values())
- except Exception as e:
- logger.info('error e=<{}>'.format(e))
- return []
- class WechatChannelApp(DynamicDocument):
- mchid = StringField(verbose_name = u'mchid', null = False)
- sslKey = StringField(verbose_name = u'PKCS8 PERM私钥内容', default = '')
- apikey_v3 = StringField(verbose_name = u'v3 api key. 加解密V3接口敏感信息', default = None)
- app_serial_number = StringField(verbose_name = u'商户证书序列号', default = None)
- platform_certificates = ListField(verbose_name = u'平台证书列表', default = None)
- appid = StringField(verbose_name = u'通道应用appid', default = None)
- search_fields = ('mchid', 'name', 'remarks')
- meta = {
- 'indexes': [
- {
- 'fields': ['mchid'], 'unique': True
- },
- ],
- 'collection': 'wechat_channel_app',
- 'db_alias': 'default'
- }
- def __repr__(self):
- return '<WechatChannelApp mchid={}>'.format(self.mchid)
- @property
- def ssl_key(self):
- return self.sslKey
- class PayAppBase(Searchable):
- meta = {
- 'abstract': True
- }
- class Function(object):
- PAY = 'pay'
- WITHDRAW = 'withdraw'
- companyName = StringField(verbose_name = u'公司名称', required = True, default = '')
- appName = StringField(verbose_name = u'应用名称', required = True, default = u'自助服务')
- remarks = StringField(verbose_name = u'备注', default = '')
- dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '添加时间')
- dateTimeUpdated = DateTimeField(verbose_name = '修改时间')
- inhouse = BooleanField(verbose_name = u'是否平台商户', default = False)
- debug = BooleanField(verbose_name = u'是否测试账号', default = False)
- agentNo = StringField(verbose_name = u'商户代理商编号', default = None)
- supportWithdraw = BooleanField(verbose_name = u'是否支持提现零钱', default = False)
- supportWithdrawBank = BooleanField(verbose_name = u'是否支持提现到银行卡', default = False)
- @property
- def pay_app_type(self):
- raise AttributeError('no pay_app_type attribute')
- @property
- def occupantId(self):
- return getattr(self, '__occupant_id__', '')
- @occupantId.setter
- def occupantId(self, occupant_id):
- self.__occupant_id__ = occupant_id
- @property
- def occupant(self):
- _obj = getattr(self, '__occupant__', None)
- if not _obj:
- _obj = ROLE.from_role_id(self.role, self.occupantId)
- self.__occupant__ = _obj
- return _obj
- @occupant.setter
- def occupant(self, occupant):
- self.__occupant__ = occupant
- self.__occupant_id__ = str(occupant.id)
- self.role = occupant.role
- @property
- def role(self):
- return self.__role__
- @role.setter
- def role(self, role):
- self.__role__ = role
- @property
- def valid(self):
- if hasattr(self, '__valid__'):
- return getattr(self, '__valid__')
- else:
- if not hasattr(self, '__valid_check__'):
- raise AttributeError('no __valid_check__ attribute')
- else:
- return getattr(self, '__valid_check__')
- @valid.setter
- def valid(self, value):
- self.__valid__ = value
- @property
- def enable(self):
- # type: ()->bool
- return getattr(self, '__enable__', True)
- @enable.setter
- def enable(self, value):
- # type: (bool)->None
- self.__enable__ = value
- @property
- def __gateway_key__(self):
- raise AttributeError('no __gateway_key__ attribute')
- @property
- def __source_key__(self):
- raise AttributeError('no __source_key__ attribute')
- @classmethod
- def get_collection(cls):
- return cls._get_collection()
- def to_dict(self):
- raise NotImplementedError('must implement to_dict method')
- @classmethod
- def list(cls, page_index, page_size, search_key):
- cursor = cls.objects().search(search_key).order_by('-dateTimeAdded')
- total = cursor.count()
- items = cursor.paginate(page_index, page_size)
- return total, [_.to_dict(True) for _ in items]
- @classmethod
- def __from_gateway_key__(cls, occupant_id, tokens):
- # type: (str, List)->cast(PayAppBase)
- raise NotImplementedError('must implement from_gateway_key class method')
- def new_gateway(self, app_platform_type):
- raise NotImplementedError('must implement new_gateway')
- def new_withdraw_gateway(self, gateway_version = None):
- raise NotImplementedError('must implement new_withdraw_gateway')
- class WechatPayApp(PayAppBase):
- """
- 对于V1接口, 需要sslKey(证书私钥)和sslCert(证书字符串)来调用接口, 使用apikey来加解密信息
- 对于V3接口, 需要sslKey(证书私钥)和app_serial_number(证书序列号)来调用接口, 使用apikey_v3来加解密信息
- """
- appid = StringField(verbose_name = u'应用ID', required = True, null = False)
- secret = StringField(verbose_name = u"secretId", required = True, null = False, max_length = 32)
- mchid = StringField(verbose_name = u'mchid', null = False)
- sslKey = StringField(verbose_name = u'PKCS8 PERM私钥内容', default = '')
- # 对于V1接口, 需要sslKey(证书私钥)和sslCert(证书字符串)来调用接口, 使用apikey来加解密信息
- apikey = StringField(verbose_name = u'apikey', null = False)
- sslCert = StringField(verbose_name = u'PERM证书内容', default = '')
- # 对于V3接口, 需要sslKey(证书私钥)和app_serial_number(证书序列号)来调用接口, 使用apikey_v3来加解密信息
- apikey_v3 = StringField(verbose_name = u'v3 api key. 加解密V3接口敏感信息', default = None)
- app_serial_number = StringField(verbose_name = u'商户证书序列号', default = None)
- platform_certificates = ListField(verbose_name = u'平台证书列表', default = None)
- withdrawV3 = BooleanField(verbose_name = u'是否使用V3接口对微信转账', default = False)
- manual_withdraw = BooleanField(verbose_name = u'是否手动提现', default = False)
- # 以下字段不在使用, 暂时兼容保留
- sslcert_path = StringField(verbose_name = '证书pem格式', default = None)
- sslkey_path = StringField(verbose_name = '证书密钥pem格式', default = None)
- rawAppId = StringField(verbose_name = u'原始ID', default = '')
- rootca_path = StringField(verbose_name = u'root证书路径', default = '')
- rootCA = StringField(verbose_name = u'root证书', default = '')
- supportWithdraw = BooleanField(verbose_name = u'是否支持提现', default = True)
- supportWithdrawBank = BooleanField(verbose_name = u'是否支持提现到银行卡', default = True)
- search_fields = ('appid', 'mchid', 'name', 'remarks')
- meta = {
- 'indexes': [
- {
- 'fields': ['appid', 'mchid'], 'unique': True
- },
- ],
- 'collection': 'wechat_pay_app',
- 'db_alias': 'default'
- }
- def __repr__(self):
- return '<WechatPayApp appid={}>'.format(self.appid)
- @property
- def __valid_check__(self):
- return bool(self.appid and self.secret and self.mchid and self.ssl_key and self.ssl_cert and self.apikey)
- @property
- def pay_app_type(self):
- return PayAppType.WECHAT
- @property
- def __gateway_key__(self):
- _ = [
- self.occupantId,
- self.appid,
- self.mchid,
- self.occupant.role
- ]
- return APP_KEY_DELIMITER.join(_)
- @property
- def __source_key__(self):
- return APP_KEY_DELIMITER.join([
- self.occupantId,
- self.mchid
- ])
- def to_dict(self, shadow = False):
- return {
- 'id': str(self.id),
- 'appid': self.appid,
- 'mchid': self.mchid,
- 'secret': encrypt_display(self.secret) if shadow else self.secret,
- 'apikey': encrypt_display(self.apikey) if shadow else self.apikey,
- 'ssl_key': base64.b64encode(self.ssl_key),
- 'ssl_cert': base64.b64encode(self.ssl_cert),
- 'manual_withdraw': self.manual_withdraw,
- 'companyName': self.companyName,
- 'appName': self.appName,
- 'remarks': self.remarks
- }
- @classmethod
- def get_null_app(cls):
- app = cls(appid = '',
- secret = '',
- mchid = '',
- apikey = '',
- sslKey = '',
- sslCert = '',
- sslcert_path = '',
- sslkey_path = '',
- manual_withdraw = False)
- app.enable = False
- app.valid = True
- app.supportWithdraw = False
- app.supportWithdrawBank = False
- return app
- @classmethod
- def __from_gateway_key__(cls, occupant_id, tokens):
- # type: (str, List)->cast(PayAppBase)
- appid, mchid = tokens[0], tokens[1]
- app = cls.objects(appid = appid, mchid = mchid).first() # type: WechatPayApp
- if not app:
- raise UserServerException(u'系统配置错误,请联系平台客服')
- app.occupantId = occupant_id
- try:
- app.role = tokens[2]
- except:
- app.role = ROLE.agent
- return app
- @classmethod
- def __from_source_key__(cls, occupant_id, tokens):
- # type: (str, List)->cast(PayAppBase)
- # TODO 查找最新加的商户号. 需要增加商户号管理功能,可以禁止,设置active等功能
- app = cls.objects(mchid = tokens[0]).order_by('-dateTimeAdded').first()
- if not app:
- raise UserServerException(u'系统配置错误(第三方支付),请联系平台客服')
- app.occupantId = occupant_id
- return app
- def new_gateway(self, app_platform_type):
- from apps.web.core.payment.wechat import WechatPaymentGateway
- return WechatPaymentGateway(self)
- def new_withdraw_gateway(self, gateway_version = 'v1'):
- from apps.web.core.payment.wechat import WechatWithdrawGateway
- if gateway_version == 'v3':
- if not self.withdrawV3 or not self.apikey_v3:
- return None
- return WechatWithdrawGateway(self, gateway_version = gateway_version)
- @property
- def ssl_cert(self):
- if not hasattr(self, '__ssl_cert__'):
- try:
- if self.sslCert.startswith('-----BEGIN'):
- setattr(self, '__ssl_cert__', self.sslCert)
- elif self.sslcert_path.startswith('-----BEGIN'):
- setattr(self, '__ssl_cert__', self.sslcert_path)
- else:
- with open(self.sslcert_path) as fp:
- setattr(self, '__ssl_cert__', fp.read())
- except Exception as e:
- logger.error('{} ssl_cert exception = {}'.format(repr(self), e.message))
- setattr(self, '__ssl_cert__', '')
- return getattr(self, '__ssl_cert__')
- @property
- def ssl_key(self):
- if not hasattr(self, '__ssl_key__'):
- try:
- if self.sslKey.startswith('-----BEGIN'):
- setattr(self, '__ssl_key__', self.sslKey)
- elif self.sslkey_path.startswith('-----BEGIN'):
- setattr(self, '__ssl_key__', self.sslkey_path)
- else:
- with open(self.sslkey_path) as fp:
- setattr(self, '__ssl_key__', fp.read())
- except Exception as e:
- logger.error('{} ssl_key exception = {}'.format(repr(self), e.message))
- setattr(self, '__ssl_key__', '')
- return getattr(self, '__ssl_key__')
- @update_certificates.connect
- def update_v3_certificates(sender, mchid, cert_str_list):
- WechatChannelApp.objects(mchid = mchid).update(platform_certificates = cert_str_list)
- WechatPayApp.objects(mchid = mchid).update(platform_certificates = cert_str_list)
- class AliApp(PayAppBase):
- appid = StringField(verbose_name = u'应用ID', required = True, null = False)
- # 参数加密秘钥. 一般不加密
- aesEncryptKey = StringField(verbose_name = u'加密秘钥', default = None)
- signKeyType = StringField(verbose_name = u'签名方式(normal,cert)', default = 'normal')
- # 公钥模式
- appPrivateKey = StringField(verbose_name = u'支付宝应用私钥. 只有测试情况下才能使用字符串', default = '')
- alipayPublicKey = StringField(verbose_name = u'文本形式支付宝账户公钥', default = '')
- # 证书模式
- appPublicKeyCert = StringField(verbose_name = u'支付宝应用公共证书', default = '')
- publicKeyCert = StringField(verbose_name = u'支付宝公共证书', default = '')
- rootCert = StringField(verbose_name = u'支付宝根证书', default = '')
- # 中间字段
- alipayPublicKeyContent = StringField(verbose_name = u'支付宝公钥文本', default = None)
- appPublicKeyContent = StringField(verbose_name = u'应用公钥文本', default = None)
- app_private_key_path = StringField(verbose_name = u'支付宝应用私钥路径', default = None)
- public_key_path = StringField(verbose_name = u'支付宝账户公钥路径', default = None)
- app_publickey_cert_path = StringField(verbose_name = u'支付宝应用公共证书路径', default = None)
- publickey_cert_path = StringField(verbose_name = u'支付宝公共证书路径', default = None)
- root_cert_path = StringField(verbose_name = u'支付宝根证书路径', default = None)
- search_fields = ('appid', 'name', 'remarks')
- meta = {
- 'indexes': [
- {
- 'fields': ['appid'], 'unique': True
- },
- ],
- 'collection': 'ali_pay_app',
- 'db_alias': 'default'
- }
- def __repr__(self):
- return '<AliApp appid={}>'.format(self.appid)
- @property
- def __valid_check__(self):
- if not self.appid:
- return False
- if self.signKeyType == 'normal':
- return bool(self.public_key_string and self.app_private_key_string)
- if self.signKeyType == 'cert':
- return bool(self.app_private_key_string and
- self.public_key_cert_string and
- self.root_cert_string and
- self.app_public_key_cert_string)
- return False
- @property
- def aes_encrypt_key(self):
- return self.aesEncryptKey
- @property
- def app_private_key_string(self):
- if not hasattr(self, '__app_private_key_string__'):
- try:
- if self.appPrivateKey.startswith('-----BEGIN'):
- setattr(self, '__app_private_key_string__', self.appPrivateKey)
- elif self.app_private_key_path and self.app_private_key_path.startswith('-----BEGIN'):
- setattr(self, '__app_private_key_string__', self.app_private_key_path)
- else:
- with open(self.app_private_key_path) as fp:
- setattr(self, '__app_private_key_string__', fp.read())
- except Exception as e:
- logger.error('{} app_private_key_string exception = {}'.format(repr(self), e.message))
- setattr(self, '__app_private_key_string__', '')
- return getattr(self, '__app_private_key_string__')
- @property
- def public_key_string(self):
- if not hasattr(self, '__public_key_string__'):
- try:
- if self.alipayPublicKey.startswith('-----BEGIN'):
- setattr(self, '__public_key_string__', self.alipayPublicKey)
- elif self.public_key_path.startswith('-----BEGIN'):
- setattr(self, '__public_key_string__', self.public_key_path)
- else:
- with open(self.public_key_path) as fp:
- setattr(self, '__public_key_string__', fp.read())
- except Exception as e:
- logger.error('{} public_key_string exception = {}'.format(repr(self), e.message))
- setattr(self, '__public_key_string__', '')
- return getattr(self, '__public_key_string__')
- @property
- def app_public_key_cert_string(self):
- if not hasattr(self, '__app_public_key_cert_string__'):
- try:
- if self.appPublicKeyCert.startswith('-----BEGIN'):
- setattr(self, '__app_public_key_cert_string__', self.appPublicKeyCert)
- else:
- with open(self.appPublicKeyCert) as fp:
- setattr(self, '__app_public_key_cert_string__', fp.read())
- except Exception as e:
- logger.error('{} app_public_key_cert_string exception = {}'.format(repr(self), e.message))
- setattr(self, '__app_public_key_cert_string__', '')
- return getattr(self, '__app_public_key_cert_string__')
- @property
- def public_key_cert_string(self):
- if not hasattr(self, '__public_key_cert_string__'):
- try:
- if self.publicKeyCert.startswith('-----BEGIN'):
- setattr(self, '__public_key_cert_string__', self.publicKeyCert)
- else:
- with open(self.publicKeyCert) as fp:
- setattr(self, '__public_key_cert_string__', fp.read())
- except Exception as e:
- logger.error('{} public_key_cert_string exception = {}'.format(repr(self), e.message))
- setattr(self, '__public_key_cert_string__', '')
- return getattr(self, '__public_key_cert_string__')
- @property
- def root_cert_string(self):
- if not hasattr(self, '__root_cert_string__'):
- try:
- if self.rootCert.startswith('-----BEGIN'):
- setattr(self, '__root_cert_string__', self.rootCert)
- else:
- with open(self.rootCert) as fp:
- setattr(self, '__root_cert_string__', fp.read())
- except Exception as e:
- logger.error('{} root_cert_string exception = {}'.format(repr(self), e.message))
- setattr(self, '__root_cert_string__', '')
- return getattr(self, '__root_cert_string__')
- @property
- def pay_app_type(self):
- return PayAppType.ALIPAY
- @property
- def __gateway_key__(self):
- _ = [
- self.occupantId,
- self.appid,
- self.occupant.role
- ]
- return APP_KEY_DELIMITER.join(_)
- def to_dict(self, shadow = False):
- return {
- 'id': str(self.id),
- 'appid': self.appid,
- 'hasAlipayAppKeyPair': bool(self.app_private_key_string is not ''),
- 'public_key_path': self.public_key_path,
- 'app_private_key_path': self.app_private_key_path,
- 'alipayPublicKey': encrypt_display(self.alipayPublicKey) if shadow else self.alipayPublicKey,
- 'appPrivateKey': encrypt_display(self.appPrivateKey) if shadow else self.appPrivateKey,
- 'alipayPublicKeyContent': encrypt_display(
- self.alipayPublicKeyContent) if shadow else self.alipayPublicKeyContent,
- 'appPublicKeyContent': encrypt_display(self.appPublicKeyContent) if shadow else self.appPublicKeyContent,
- 'debug': self.debug,
- 'appName': self.appName,
- 'companyName': self.companyName
- }
- @classmethod
- def get_null_app(cls):
- app = cls(appid = '', public_key_path = '', app_private_key_path = '', shadow = False)
- app.enable = False
- app.valid = True
- app.supportWithdraw = False
- app.supportWithdrawBank = False
- return app
- @classmethod
- def __from_gateway_key__(cls, occupant_id, tokens):
- # type: (str, List)->cast(PayAppBase)
- appid = tokens[0]
- app = cls.objects(appid = appid).first() # type: AliApp
- if not app:
- raise UserServerException(u'系统配置错误,请联系平台客服(10005)')
- app.occupantId = occupant_id
- try:
- app.role = tokens[1]
- except:
- app.role = ROLE.agent
- return app
- def new_gateway(self, app_platform_type):
- from apps.web.core.payment.ali import AliPayGateway
- return AliPayGateway(self)
- def new_withdraw_gateway(self, gateway_version = None):
- from apps.web.core.payment.ali import AliPayWithdrawGateway
- return AliPayWithdrawGateway(self)
- @property
- def client(self):
- if hasattr(self, '__client__'):
- return getattr(self, '__client__')
- if self.signKeyType not in ['normal', 'cert']:
- raise AliException(
- errCode = -1,
- errMsg = u'参数配置错误',
- client = None)
- params = {
- 'appid': self.appid,
- 'sign_type': "RSA2",
- 'debug': self.debug,
- 'timeout': 15
- }
- params.update({'app_private_key_string': self.app_private_key_string})
- if self.signKeyType == 'normal':
- params.update({'public_key_string': self.public_key_string})
- setattr(self, '__client__', AliPay(**params))
- if self.signKeyType == 'cert':
- params.update({
- 'public_key_cert_string': self.public_key_cert_string,
- 'root_cert_string': self.root_cert_string,
- 'app_public_key_cert_string': self.app_public_key_cert_string,
- 'aes_encrypt_key': self.aes_encrypt_key
- })
- setattr(self, '__client__', DCAliPay(**params))
- return getattr(self, '__client__')
- @property
- def withdraw_payer_info(self):
- return None
- def withdraw_product_code(self, bank):
- if bank:
- return 'TRANS_BANKCARD_NO_PWD'
- else:
- return 'TRANS_ACCOUNT_NO_PWD'
- def withdraw_biz_scene(self, bank):
- return 'DIRECT_TRANSFER'
- class AliFundAccountBookApp(PayAppBase):
- """
- 阿里资金转账APP
- """
- appid = StringField(verbose_name = u'资金记账本id', required = True, null = False)
- agreementNo = StringField(verbose_name = u'协议编号', required = True, null = False)
- certNo = StringField(verbose_name = u'企业营业执照认证号')
- merchantUserId = StringField(verbose_name = u'外部商户系统会员的唯一标识;创建记账本的幂等字段')
- merchantUserType = StringField(verbose_name = u'外部商户用户类型,固定值')
- sceneCode = StringField(verbose_name = u'资金记账本的业务场景')
- cardInfo = DictField(verbose_name = u'虚拟银行卡信息')
- search_fields = ('appid', 'name', 'remarks')
- meta = {
- 'indexes': [
- {
- 'fields': ['appid'], 'unique': True
- },
- ],
- 'collection': 'ali_fund_account_book',
- 'db_alias': 'default'
- }
- def __repr__(self):
- return '<AliFundAccountBookApp appid={}>'.format(self.appid)
- @classmethod
- def make_user_id(cls, external_agreement_no, cert_no):
- return '{}{}'.format(external_agreement_no, cert_no)
- @classmethod
- def apply(cls, signModel):
- # type: (AliUserAgreementSign)->AliFundAccountBookApp
- return cls(
- agentNo = signModel.cooperAppId,
- merchantUserId = cls.make_user_id(signModel.externalAgreementNo, signModel.attachParas['certNo']),
- merchantUserType = 'BUSINESS_ORGANIZATION',
- sceneCode = 'SATF_FUND_BOOK',
- agreementNo = signModel.agreementNo,
- certNo = signModel.attachParas['certNo']
- )
- @property
- def __valid_check__(self):
- if not self.appid or not self.agreementNo:
- return False
- else:
- return True
- @cached_property
- def ISVApp(self):
- return AliApp.objects(appid = self.agentNo).first()
- @property
- def support_withdraw(self):
- return self.ISVApp.supportWithdraw
- @property
- def support_withdraw_bank(self):
- return self.ISVApp.supportWithdrawBank
- @property
- def withdraw_payer_info(self):
- return {
- 'identity_type': 'ACCOUNT_BOOK_ID',
- 'identity': self.appid,
- 'ext_info': json.dumps({
- 'agreement_no': self.agreementNo
- })
- }
- def withdraw_product_code(self, bank):
- return 'SINGLE_TRANSFER_NO_PWD'
- def withdraw_biz_scene(self, bank):
- return 'ENTRUST_TRANSFER'
- def new_withdraw_gateway(self, gateway_version = None):
- from apps.web.core.payment.ali import AliPayWithdrawGateway
- return AliPayWithdrawGateway(self)
- @property
- def pay_app_type(self):
- return PayAppType.ALIPAY_FUND_BOOK
- @property
- def __gateway_key__(self):
- _ = [
- self.occupantId,
- self.appid,
- self.occupant.role
- ]
- return APP_KEY_DELIMITER.join(_)
- @property
- def client(self):
- if hasattr(self, '__client__'):
- return getattr(self, '__client__')
- _client = self.ISVApp.client
- setattr(self, '__client__', _client)
- return _client
- class PlatformAppBase(PayAppBase):
- """
- 平台记账APP
- """
- meta = {
- 'abstract': True
- }
- APP_NAME = ''
- @property
- def __valid_check__(self):
- return True
- @property
- def __gateway_key__(self):
- _ = [
- settings.MY_PRIMARY_AGENT_ID,
- ROLE.agent
- ]
- return APP_KEY_DELIMITER.join(_)
- @classmethod
- def get_app(cls):
- app = cls()
- app.role = ROLE.agent
- app.occupantId = settings.MY_PRIMARY_AGENT_ID
- app.enable = True
- app.valid = True
- app.inhouse = True
- app.debug = False
- app.companyName = u'武汉大源科技有限公司'
- app.appName = cls.APP_NAME
- return app
- @classmethod
- def __from_gateway_key__(cls, occupant_id, tokens):
- # type: (str, List)->cast(PayAppBase)
- assert occupant_id == settings.MY_PRIMARY_AGENT_ID, u'非法GatewayKey'
- return cls.get_app()
- class PlatformPromotionApp(PlatformAppBase):
- """
- 用于平台记账后 分账给其他人, 例如红包受益 广告收益等 分给经销商
- """
- meta = {
- 'abstract': True
- }
- APP_NAME = u'平台补贴'
- def __repr__(self):
- return '<platform promotion App>'
- def new_gateway(self, app_platform_type):
- from apps.web.core.payment.platform import PlatformPromotionPaymentGateway
- return PlatformPromotionPaymentGateway(self, app_platform_type)
- @property
- def pay_app_type(self):
- return PayAppType.PLATFORM_PROMOTION
- class PlatformReconcileApp(PlatformAppBase):
- """
- 平台对账后建立订单分账
- """
- meta = {
- 'abstract': True
- }
- APP_NAME = u'平台对账'
- def __repr__(self):
- return '<platform reconcile App>'
- def new_gateway(self, app_platform_type):
- from apps.web.core.payment.platform import PlatformReconcilePaymentGateway
- return PlatformReconcilePaymentGateway(self, app_platform_type)
- @property
- def pay_app_type(self):
- return PayAppType.PLATFORM_RECONCILE
- class PlatformWalletApp(PlatformPromotionApp):
- """
- 用于使用经销商余额(平台资金池)进行SIM卡支付
- """
- meta = {
- 'abstract': True
- }
- def __repr__(self):
- return '<platform wallet App>'
- def new_gateway(self, app_platform_type):
- from apps.web.core.payment.platform import PlatformWalletPaymentGateway
- return PlatformWalletPaymentGateway(self, app_platform_type)
- @property
- def pay_app_type(self):
- return PayAppType.PLATFORM_WALLET
- class LedgerConsumeApp(PayAppBase):
- meta = {
- 'abstract': True
- }
- APP_NAME = u'消费分账'
- @property
- def pay_app_type(self):
- return PayAppType.LEDGER_CONSUME
- def new_gateway(self, app_platform_type):
- from apps.web.core.payment.consume import LedgerConsumePaymentGateway
- return LedgerConsumePaymentGateway(self, app_platform_type)
- @classmethod
- def get_app(cls, dealer): # type:(Dealer) -> LedgerConsumeApp
- app = cls()
- app.role = ROLE.agent
- app.occupantId = settings.MY_PRIMARY_AGENT_ID
- app.enable = True
- app.valid = True
- app.inhouse = True
- app.debug = False
- app.appName = cls.APP_NAME
- return app
- class ManualPayApp(PayAppBase):
- """
- 客户线下打款后, 超级管理员建立充值记录
- """
- def __repr__(self):
- return '<manual pay App>'
- @property
- def __valid_check__(self):
- return True
- def new_gateway(self, app_platform_type):
- from apps.web.core.payment.manual import ManualPaymentGateway
- return ManualPaymentGateway(self, app_platform_type)
- @property
- def pay_app_type(self):
- return PayAppType.MANUAL
- @property
- def __gateway_key__(self):
- _ = [
- self.occupantId,
- self.occupant.role
- ]
- return APP_KEY_DELIMITER.join(_)
- @classmethod
- def get_null_app(cls):
- app = cls()
- app.enable = True
- app.valid = True
- return app
- @classmethod
- def __from_gateway_key__(cls, occupant_id, tokens):
- # type: (str, List)->cast(PayAppBase)
- app = cls.get_null_app() # type: ManualPayApp
- app.occupantId = occupant_id
- try:
- app.role = tokens[1]
- except:
- app.role = ROLE.agent
- return app
- class WechatComponentApp(DynamicDocument):
- appid = StringField(verbose_name='appid', default='', required=True)
- secret = StringField(verbose_name="secretId", default='', required=True)
- aesKey = StringField(verbose_name="aesKey", default='', required=True)
- token = StringField(verbose_name="token", default='', required=True)
- companyName = StringField(verbose_name="companyName", default='')
- appName = StringField(verbose_name="appName", default='')
- meta = {
- 'collection': 'wechat_component_app'
- }
- class WechatAuthorizer(DynamicDocument):
- appid = StringField(verbose_name='appid', default='', required=True)
- appType = IntField(verbose_name='appType(0-mini,1-biz)', default=1)
- serviceType = IntField(verbose_name='serviceType', default=2)
- verifyInfo = IntField(verbose_name='verifyInfo')
- nickName = StringField(verbose_name='appType', default='')
- userName = StringField(verbose_name='appType', default='')
- headImg = StringField(verbose_name='appType', default='')
- qrcodeUrl = StringField(verbose_name='appType', default='')
- principalName = StringField(verbose_name='appType', default='')
- funcList = ListField(verbose_name='funcList', default=[])
- appStatus = IntField(verbose_name='appStatus')
- extra = DictField(verbose_name='extra', default={})
- refreshToken = StringField(verbose_name='appType', default='')
- updateTime = DateTimeField(default=datetime.datetime.now, verbose_name=u'授权时间')
- dtAdded = DateTimeField(default=datetime.datetime.now, verbose_name=u'授权时间')
- authState = StringField(verbose_name='authState', default='authorized')
- meta = {
- 'collection': 'wechat_authorizer'
- }
- REFRESH_TOKEN_KEY = 'refresh_token_{}'
- @classmethod
- def getAuthRecord(cls, appid):
- token = serviceCache.get(cls.REFRESH_TOKEN_KEY.format(appid))
- if not token:
- authorizer = cls.objects(appid=appid).first()
- if authorizer:
- token = authorizer.refreshToken
- serviceCache.set(cls.REFRESH_TOKEN_KEY.format(settings.WECHAT_3RD_APPID), token)
- return token
- @classmethod
- def createOrUpdateAuthRecord(cls, payload):
- payload.update({
- 'authState': 'authorized',
- 'updateTime': datetime.datetime.now()
- })
- cls.objects(appid=payload['appid']).update_one(upsert=True, **payload)
- @classmethod
- def deleteAuthRecord(cls, appid):
- cls.objects(appid=appid).update_one(
- appid=appid, authState='unauthorized', updateTime=datetime.datetime.now())
- class WithdrawEntity(EmbeddedDocument):
- wechatWithdrawApp = LazyReferenceField(document_type = WechatPayApp, default = None)
- alipayWithdrawApp = LazyReferenceField(document_type = AliApp, default = None)
- aliWithdrawApp = GenericLazyReferenceField(choices = [AliApp, AliFundAccountBookApp], default = None)
- @property
- def alipay_app(self):
- if self.aliWithdrawApp:
- return self.aliWithdrawApp.fetch()
- elif self.alipayWithdrawApp:
- return self.alipayWithdrawApp.fetch()
- else:
- return None
- @property
- def wechat_app(self):
- if self.wechatWithdrawApp:
- return self.wechatWithdrawApp.fetch()
- else:
- return None
- class BoundOpenInfo(EmbeddedDocument):
- openId = StringField(required = True, default = '')
- avatar = StringField(default = '')
- sex = IntField(verbose_name = "性别", default = Const.USER_SEX.UNKNOWN)
- nickname = StringField(verbose_name = "昵称", default = "")
- def to_dict(self):
- return {
- 'openId': self.openId
- }
- def to_detail_dict(self):
- return {
- "openId": self.openId,
- "avatar": self.avatar,
- "sex": self.sex,
- "nickname": self.nickname
- }
- class OfflineTask(Searchable):
- _STATUS_MAP = Const.CELERY_TASK_RESULT_TRANSLATION
- name = StringField(verbose_name = '任务名称')
- type = StringField(verbose_name = '类型')
- status = StringField(verbose_name = '状态', default = 'PENDING')
- result = StringField(verbose_name = '执行结果详细信息', default = '')
- link = StringField(verbose_name = '链接')
- celery_task_id = StringField(verbose_name = 'celery侧uuid', default = '')
- process_func_name = StringField(verbose_name = '任务的函数名')
- role = StringField(verbose_name = '角色', choices = ROLE.choices())
- ownerId = ObjectIdField(verbose_name = '创建者ID')
- dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = '任务生成时间')
- finishedTime = DateTimeField(verbose_name = '完成时间', default = None)
- search_fields = ('id', 'celery_task_id', 'name')
- meta = {
- 'collection': 'offline_task',
- 'db_alias': 'logdata',
- 'indexes': [
- {
- 'fields': ['ownerId', 'role']
- }
- ],
- }
- def to_dict(self):
- return {
- 'id': str(self.id),
- 'name': self.name,
- 'status': self.status,
- 'result': self.result,
- 'link': self.link,
- 'celery_task_id': self.celery_task_id,
- 'type': self.type,
- 'startTime': self.dateTimeAdded,
- 'finishedTime': self.finishedTime
- }
- @classmethod
- def issue_export_report(cls, offline_task_name, process_func_name, task_type, userid, role, ext = 'xlsx'):
- file_path = '{}reports/{}/{}.{}'.format(
- settings.MEDIA_URL,
- datetime.datetime.now().strftime("%Y%m%d"),
- offline_task_name,
- ext)
- if settings.UPLOAD_REPORT_TO_OSS:
- link = '{}{}'.format(settings.OSS_RESOURCE_URL, file_path)
- else:
- link = '{}{}?local=true'.format(settings.LOCAL_REPORT_URL, file_path)
- offline_task = OfflineTask(
- name = offline_task_name,
- type = task_type,
- process_func_name = process_func_name,
- ownerId = userid,
- role = role,
- link = link)
- offline_task.save()
- return file_path[1:], offline_task
- @classmethod
- def issue(cls, offline_task_name, process_func_name, task_type, userid, role):
- offline_task = OfflineTask(
- name = offline_task_name,
- type = task_type,
- process_func_name = process_func_name,
- ownerId = userid,
- role = role)
- offline_task.save()
- return offline_task
- class BankCard(Searchable):
- """
- TODO: 已经废弃.升级脚本暂时需要, 下个版本后删除
- """
- class AccountType(object):
- PERSONAL = 'personal'
- PUBLIC = 'public'
- bankName = StringField(verbose_name = u"银行名称", required = True)
- branchName = StringField(verbose_name = u"支行信息")
- cardNo = StringField(verbose_name = u"银行卡号", required = True, unique = True)
- cardType = StringField(verbose_name = u"卡类型", default = "debit")
- remark = StringField(verbose_name = u"备注", default = "")
- # category = StringField(verbose_name=u"所属类别,个人或者公司", default='individual')
- province = StringField(verbose_name = u"省级别开户地址信息", default = "")
- city = StringField(verbose_name = u"市级别开户地址信息", default = "")
- district = StringField(verbose_name = u"区级别开户地址信息", default = "")
- holderName = StringField(verbose_name = u"开户人姓名", required = True)
- code = StringField(verbose_name = u"微信支持银行卡所对应的code(银行编号), 默认为0000表示不支持", default = "0000")
- cnapsCode = StringField(verbose_name = u'支行联行号', default = '')
- is_valid = BooleanField(verbose_name = u"是否是有效卡", default = True)
- is_primary = BooleanField(verbose_name = u"优先选择", default = True)
- manual = BooleanField(verbose_name = u"该卡是否仅手动提现", default = False)
- accountType = StringField(verbose_name = u'卡类型(个人账号,对公账号)', default = AccountType.PERSONAL)
- meta = {"collection": "bankcards", "db_alias": "default"}
- class SystemSettings(Searchable):
- key = StringField(verbose_name = u'设置名称')
- value = DynamicField(verbose_name = u'设置参数')
- desc = StringField(verbose_name = u'设置描述')
- dateTimeAdded = DateTimeField(default = datetime.datetime.now, verbose_name = u'添加时间')
- meta = {
- 'collection': 'system_settings'
- }
- all_settings = {}
- load_ready = False
- @classmethod
- def get_system_setting(cls, setting_name, default = None):
- if not cls.load_ready:
- cls.load_settings()
- return cls.all_settings.get(setting_name, default)
- @classmethod
- def load_settings(cls):
- cls.all_settings = {item.key: item.value for item in cls.objects.all()}
- cls.load_ready = True
- @classmethod
- def reload_settings(cls):
- logger.debug("reload system settings.")
- cls.load_ready = False
- cls.load_settings()
- @classmethod
- def set_setting(cls, key, value):
- cls.objects(key=key).update_one(upsert=True, **{"value": value})
- cls.all_settings[key] = value
- @classmethod
- def set_mem_setting(cls, key, value):
- cls.all_settings[key] = value
- @classmethod
- def get_support_redpack_list(cls):
- obj = cls.objects.filter(key='SUPPORT_REDPACK_LIST').first()
- if obj:
- return json_loads(obj.value)
- else:
- return []
- @classmethod
- def set_support_redpack_list(cls, dataList):
- value = json_dumps(dataList)
- return cls.objects.filter(key='SUPPORT_REDPACK_LIST').update(value=value)
- @classmethod
- def disable_alipay_ruhui(cls):
- item = cls.objects.filter(key='DISABLE_REDPACK').first()
- if not item:
- vaule = {}
- else:
- vaule = item.value
- return vaule.get('RUHUI', False)
- @classmethod
- def disable_alipay_laxin(cls):
- item = cls.objects.filter(key='DISABLE_REDPACK').first()
- if not item:
- vaule = {}
- else:
- vaule = item.value
- return vaule.get('LAXIN', False)
- @classmethod
- def get_system_setting_direct(cls, setting_name, default = None):
- obj = cls.objects.filter(key = setting_name).first()
- if obj:
- return obj.value
- else:
- return default
- class DriverCode(Searchable):
- code = StringField(verbose_name = u'驱动编码', unique = True)
- name = StringField(verbose_name = u'驱动名称', unique = True)
- description = StringField(verbose_name = u'驱动描述')
- createdTime = DateTimeField(default = datetime.datetime.now, verbose_name = u'添加进来的时间')
- adapterFile = StringField(verbose_name = '业务处理文件名称', default = '')
- adapterVer = StringField(verbose_name = '业务版本', default = '2.0') # 发生变化后,会自动化加载
- adapter = StringField(verbose_name = '适配器类名称', default = '')
- eventerFile = StringField(verbose_name = '事件处理文件名称', default = '')
- eventerVer = StringField(verbose_name = '事件处理版本', default = '2.0') # 发生变化后,会自动化加载
- features = DictField(verbose_name = "额外特征", default = {}) # 属于某个设备类型的特征
- meta = {'collection': 'device_driver_code', 'db_alias': 'default'}
- def __repr__(self):
- return '<DriverCode code=%s>' % (self.code,)
- def to_dict(self):
- return {
- 'code': self.code,
- 'name': self.name,
- 'features': self.features,
- 'description': self.description
- }
- @classmethod
- def get_driver_code(cls, code):
- # type: (str)->dict
- cache_key = lambda code: 'driverCode{}'.format(code)
- if not code: return None
- driverInfo = cache.get(cache_key(code))
- if driverInfo:
- return driverInfo
- else:
- obj = cls.objects(code = code).first() # type: DriverCode
- if obj:
- value = {
- 'id': str(obj.id),
- 'code': obj.code,
- 'name': obj.name,
- 'description': obj.description,
- 'createdTime': obj.to_datetime_str(obj.createdTime),
- 'adapterFile': obj.adapterFile,
- 'eventerFile': obj.eventerFile,
- 'features': dict(obj.features)
- }
- cache.set(cache_key(code), value)
- return value
- return None
- class DriverAdapter(DynamicDocument):
- adapterFile = StringField(verbose_name = '业务处理文件名称', unique = True)
- adapterVer = StringField(verbose_name = '业务版本', default = '1.0')
- adapter = StringField(verbose_name = '适配器类名称', default = '')
- meta = {'collection': 'device_driver_adapter', 'db_alias': 'default'}
- _lock = ThreadLock()
- adapters = {}
- def to_dict(self):
- return {
- 'adapterFile': self.adapterFile,
- 'adapterVer': self.adapterVer,
- 'adapter': self.adapter
- }
- @classmethod
- def get_driver_adapter(cls, code, dev, online = True):
- cache_key = lambda filename: 'driverAdapter{}'.format(filename)
- adapter_file = None
- if not online:
- adapter_file = 'offline'
- else:
- driver_code_info = DriverCode.get_driver_code(code)
- if driver_code_info:
- adapter_file = driver_code_info['adapterFile']
- if not adapter_file:
- adapter_file = 'commonPulse'
- adapter_info = cache.get(cache_key(adapter_file))
- if not adapter_info:
- adapter = cls.objects.get(adapterFile = adapter_file)
- adapter_info = {
- 'adapterFile': adapter.adapterFile,
- 'adapterVer': adapter.adapterVer,
- 'adapter': adapter.adapter
- }
- cache.set(cache_key(adapter_file), {
- 'adapterFile': adapter_info['adapterFile'],
- 'adapterVer': adapter_info['adapterVer'],
- 'adapter': adapter_info['adapter']
- })
- logger.debug('[cache] load driver adapter info is: {}'.format(adapter_info))
- mem_info = cls.adapters.get(adapter_file, None)
- if mem_info and 'module' in mem_info and \
- mem_info['adapterVer'] == adapter_info['adapterVer'] and \
- mem_info['adapterFile'] == adapter_info['adapterFile'] and \
- mem_info['adapter'] == adapter_info['adapter']:
- adapter_module = cls.adapters[adapter_file]['module']
- logger.debug('adapter module {} has loaded.'.format(adapter_module))
- else:
- try:
- cls._lock.acquire_lock()
- mem_info = cls.adapters.get(adapter_file, None)
- if mem_info and 'module' in mem_info and \
- mem_info['adapterVer'] == adapter_info['adapterVer'] and \
- mem_info['adapterFile'] == adapter_info['adapterFile'] and \
- mem_info['adapter'] == adapter_info['adapter']:
- adapter_module = cls.adapters[adapter_file]['module']
- logger.debug('adapter module {} has loaded.'.format(adapter_module))
- else:
- if adapter_file in cls.adapters:
- mem_info = cls.adapters[adapter_file]
- logger.info('device adapter changed, need reload, oldInfo=%s, newInfo=%s' % (
- mem_info, adapter_info))
- module_name = 'apps.web.core.adapter.{}'.format(adapter_info['adapterFile'])
- adapter_module = import_module(module_name)
- logger.info('finished import new module = {}'.format(adapter_module))
- adapter_module = eval('reload({})'.format(module_name))
- logger.info('finished reload new module = {}'.format(adapter_module))
- adapter_info.update({'module': adapter_module})
- cls.adapters[adapter_file] = adapter_info
- else:
- logger.info('loading device adapter, adapter info = {}'.format(adapter_info))
- module_name = 'apps.web.core.adapter.{}'.format(adapter_file)
- adapter_module = import_module(module_name)
- logger.info('finished import new module = {}'.format(adapter_module))
- adapter_info.update({'module': adapter_module})
- cls.adapters[adapter_file] = adapter_info
- finally:
- cls._lock.release_lock()
- return eval('adapter_module.%s(dev)' % (adapter_info['adapter']))
- class DriverEventer(DynamicDocument):
- eventerFile = StringField(verbose_name = '事件处理文件名称', unique = True)
- eventerVer = StringField(verbose_name = '事件处理版本', default = '1.0') # 发生变化后,会自动化加载
- meta = {'collection': 'device_driver_eventer', 'db_alias': 'default'}
- _lock = ThreadLock()
- eventers = {}
- def to_dict(self):
- return {
- 'id': str(self.id),
- 'eventerFile': self.eventerFile,
- 'eventerVer': self.eventerVer
- }
- @classmethod
- def get_driver_eventer(cls, code, device_adapter, online = True):
- cache_key = lambda filename: 'driverEventer{}'.format(filename)
- eventer_file = None
- if not online:
- eventer_file = 'offline'
- else:
- driver_code_info = DriverCode.get_driver_code(code)
- if driver_code_info:
- eventer_file = driver_code_info['eventerFile']
- if not eventer_file:
- if device_adapter.__class__.__name__ == 'CommonPulseAdapter':
- eventer_file = 'commonPulse'
- else:
- eventer_file = 'dummy'
- eventer_info = cache.get(cache_key(eventer_file))
- if not eventer_info:
- eventer = cls.objects.get(eventerFile = eventer_file)
- eventer_info = {'eventerFile': eventer.eventerFile, 'eventerVer': eventer.eventerVer}
- logger.debug('load driver eventer info is: {}'.format(eventer_info))
- cache.set(cache_key(eventer_file),
- {
- 'eventerFile': eventer_info['eventerFile'],
- 'eventerVer': eventer_info['eventerVer']
- })
- mem_info = cls.eventers.get(eventer_file, None)
- if mem_info and 'module' in mem_info and mem_info['eventerVer'] == eventer_info['eventerVer'] and \
- mem_info['eventerFile'] == eventer_info['eventerFile']:
- eventer_module = mem_info['module']
- logger.debug('eventer module {} has loaded.'.format(eventer_module))
- else:
- try:
- cls._lock.acquire_lock()
- mem_info = cls.eventers.get(eventer_file, None)
- if mem_info and 'module' in mem_info and mem_info['eventerVer'] == eventer_info['eventerVer'] and \
- mem_info['eventerFile'] == eventer_info['eventerFile']:
- eventer_module = mem_info['module']
- logger.debug('eventer module {} has loaded.'.format(eventer_module))
- else:
- if mem_info:
- logger.info(
- 'device eventer changed, need reload, oldInfo = %s, newInfo = %s' % (
- mem_info, eventer_info))
- module_name = 'apps.web.eventer.{}'.format(eventer_file)
- eventer_module = import_module(module_name)
- logger.info('finished import new eventer module = {}'.format(eventer_module))
- eventer_module = eval('reload({})'.format(module_name))
- logger.info('finished reload new eventer module = {}'.format(eventer_module))
- eventer_info.update({'module': eventer_module})
- cls.eventers[eventer_file] = eventer_info
- else:
- logger.info('loading device eventer, eventer info = {}'.format(eventer_info))
- module_name = 'apps.web.eventer.{}'.format(eventer_file)
- eventer_module = import_module(module_name)
- logger.info('finished import new eventer module = {}'.format(eventer_module))
- eventer_info.update({'module': eventer_module})
- cls.eventers[eventer_file] = eventer_info
- finally:
- cls._lock.release_lock()
- return eval('eventer_module.builder(device_adapter)')
- class AliUserAgreementSign(Searchable):
- """
- 阿里用户签约
- """
- class SignStatus(IterConstant):
- INIT = 'INIT'
- TEMP = 'TEMP'
- NORMAL = 'NORMAL'
- STOP = 'STOP'
- externalAgreementNo = StringField(verbose_name = u"商户传入的协议编号")
- agreementNo = StringField(verbose_name = u"签约号")
- personalProductCode = StringField(verbose_name = u'个人产品码')
- signScene = StringField(verbose_name = u'场景码')
- accessParams = DictField(verbose_name = u'端类型')
- productCode = StringField(verbose_name = u"商家签约的产品码")
- thirdPartyType = StringField(verbose_name = u"商家类型")
- externalLogonId = StringField(verbose_name = u"用户在商户网站的登录账号,用于在签约页面展示,如果为空,则不展示")
- dateTimeAdded = DateTimeField(verbose_name = u"创建时间")
- signTime = DateTimeField(verbose_name = u"创建时间")
- attachParas = DictField(verbose_name = u'签约完成后操作所需要的参数')
- cooperAppId = StringField(verbose_name = u'合作单位APPID')
- meta = {"collection": "ali_user_agreement_sign", "db_alias": "default"}
- @classmethod
- def issue(cls, cooperAppId, external_agreement_no, external_logon_id, attach):
- return cls(
- cooperAppId = cooperAppId,
- externalAgreementNo = external_agreement_no,
- personalProductCode = 'FUND_SAFT_SIGN_WITHHOLDING_P',
- signScene = 'INDUSTRY|SATF_ACC',
- accessParams = {"channel": "QRCODE"},
- productCode = 'FUND_SAFT_SIGN_WITHHOLDING',
- thirdPartyType = 'PARTNER',
- externalLogonId = external_logon_id,
- attachParas = attach).save()
- @classmethod
- def makeNo(cls, external_logon_id):
- identifier = hashlib.md5(external_logon_id.encode()).hexdigest().upper()
- return OrderNoMaker.make_order_no_32(
- identifier, OrderMainType.OTHER, OtherOrderSubType.ALI_USER_AGREEMENT_SIG)
|