# coding=utf-8 import time import os from django.conf import settings from django.db import models from django.utils import timezone from apps.WechatTp.models import WechatTp from utils.wx.wechat import WeChat from utils.exceptions import CustomError from utils.file_operation import CertPath class WechatApplet(models.Model): AUDIT_SUCCESS = 0 AUDIT_REJECT = 1 AUDITING = 2 RECALL = 3 AUDIT_DELAY = 4 AUDIT_STATUS_CHOICE = ( (AUDIT_SUCCESS, u'审核通过'), (AUDIT_REJECT, u'审核拒绝'), (AUDITING, u'审核中'), (RECALL, u'已撤回'), (AUDIT_DELAY, u'审核延后'), ) # agent = models.ForeignKey(Agent, verbose_name=u'代理商', on_delete=models.PROTECT, null=True, editable=False) wechat_tp = models.ForeignKey(WechatTp, verbose_name=u'第三方平台', on_delete=models.PROTECT, editable=False) authorizer_appid = models.CharField(max_length=512, verbose_name=u'授权方appid') secret = models.CharField(max_length=512, verbose_name=u'小程序秘钥', null=True) authorizer_refresh_token = models.CharField(max_length=512, verbose_name=u'刷新令牌') authorizer_access_token = models.CharField(max_length=512, verbose_name=u'令牌') access_token_gtime = models.DateTimeField(verbose_name=u"获取令牌时间") expires_in = models.IntegerField(verbose_name=u'令牌有效期') is_authorize = models.BooleanField(verbose_name=u'是否授权', default=False) message_template_id = models.CharField(max_length=255, verbose_name=u'消息模版ID', null=True) nick_name = models.CharField(max_length=255, verbose_name=u'昵称', default="") head_img = models.CharField(max_length=255, verbose_name=u'头像', default="") principal_name = models.CharField(max_length=255, verbose_name=u'主体名称', default="") qrcode_url = models.CharField(max_length=512, verbose_name=u'二维码', default="") user_version = models.CharField(max_length=512, verbose_name=u'当前程序版本', default="") template_id = models.CharField(max_length=512, verbose_name=u'当前模板', default="") agent_num = models.CharField(max_length=512, verbose_name=u'商户号', default="") agent_key = models.CharField(max_length=512, verbose_name=u'商户密钥', default="") apiclient_cert = models.CharField(max_length=255, verbose_name=u'API证书cert', default="") apiclient_key = models.CharField(max_length=255, verbose_name=u'API证书key', default="") auditid = models.CharField(max_length=512, verbose_name=u'待审核ID', default="") wait_audit_version = models.CharField(max_length=512, verbose_name=u'待审核版本', null=True) wait_audit_template = models.CharField(max_length=512, verbose_name=u'待审核模板', null=True) audit_status = models.IntegerField(choices=AUDIT_STATUS_CHOICE, verbose_name=u'审核状态', null=True) reject_reason = models.CharField(max_length=512, verbose_name=u'拒绝原因', default="") is_admin = models.BooleanField(verbose_name=u'是管理者小程序', default=False) # 会员信息的小程序属于管理者小程序,其他是代理商小程序 class Meta: db_table = "wechat_applet" ordering = ['-id'] index_together = () verbose_name = u"代理商小程序" default_permissions = () permissions = [ ('manage_wechat_applet', u'管理'), ] @staticmethod def getById(id): try: id = int(id) except: raise CustomError(u'无效的小程序ID!') instance = WechatApplet.objects.filter(pk=id).first() if not instance: raise CustomError(u'未找到相应的小程序!') return instance @staticmethod def getByAppid(appid): instance = WechatApplet.objects.filter(authorizer_appid=appid, is_authorize=True).first() if not instance: raise CustomError(u'未找到相应的小程序!') return instance @staticmethod def addAuthorizer(wechat_component, authorization_code, agent): gtime = timezone.now() component_appid = wechat_component.getAppid() component_access_token = wechat_component.getAccessToken() res = WeChat.getAuthorizationInfo(component_appid, authorization_code, component_access_token) ares = WeChat.getAuthorizerInfo(component_appid, res['authorization_info']['authorizer_appid'], component_access_token) authorizer = WechatApplet.getByAppidAndComponentAppid(res['authorization_info']['authorizer_appid'], component_appid) if authorizer: if authorizer.is_authorize: raise CustomError(u'该小程序已授权!') authorizer.refresh(res['authorization_info'], ares['authorizer_info'], gtime, agent) else: authorizer = WechatApplet.objects.create( agent=agent, wechat_tp=wechat_component, authorizer_appid=res['authorization_info']['authorizer_appid'], authorizer_refresh_token=res['authorization_info']['authorizer_refresh_token'], authorizer_access_token=res['authorization_info']['authorizer_access_token'], access_token_gtime=gtime, expires_in=res['authorization_info']['expires_in'], principal_name=ares['authorizer_info']['principal_name'], nick_name=ares['authorizer_info']['nick_name'], head_img=ares['authorizer_info']['head_img'], qrcode_url=ares['authorizer_info']['qrcode_url'], is_authorize=True ) # 设置服务器域名 authorizer.setDomain() return authorizer @staticmethod def getByAppidAndComponentAppid(appid, component_appid): authorizer = WechatApplet.objects.filter(authorizer_appid=appid, wechat_tp__component_appid=component_appid).first() return authorizer def getComponent(self): return self.wechat_tp def getAccessToken(self): if self.authorizer_access_token: last_time = time.mktime(self.access_token_gtime.timetuple()) + self.expires_in now = time.mktime(timezone.now().timetuple()) if last_time > now: return self.authorizer_access_token gtime = timezone.now() res = WeChat.getAccessToken(self.authorizer_appid, self.secret) self.refreshAccessToken(gtime, res['access_token'], res['expires_in']) return self.authorizer_access_token def getAccessToken2(self): # 绑定第三方平台小程序,获取token if self.authorizer_access_token: last_time = time.mktime(self.access_token_gtime.timetuple()) + self.expires_in now = time.mktime(timezone.now().timetuple()) if last_time > now: return self.authorizer_access_token if not self.authorizer_refresh_token: return '' gtime = timezone.now() component = self.getComponent() res = WeChat.getAuthorizerAccessToken(component.getAppid(), self.authorizer_appid, self.authorizer_refresh_token, component.getAccessToken()) self.refreshAccessToken(gtime, res['authorizer_access_token'], res['expires_in'], res['authorizer_refresh_token']) return self.authorizer_access_token def revoke(self): agent = self.agent agent.is_bind_app = False agent.save() self.is_authorize = False self.save() def refreshAccessToken(self, gtime, access_token, expires_in, refresh_token=''): self.authorizer_access_token = access_token self.access_token_gtime = gtime self.expires_in = expires_in self.authorizer_refresh_token = refresh_token self.save() def refresh(self, authorization_info, authorizer_info, access_token_gtime, agent): self.authorizer_refresh_token = authorization_info['authorizer_refresh_token'] self.authorizer_access_token = authorization_info['authorizer_access_token'] self.access_token_gtime = access_token_gtime self.expires_in = authorization_info['expires_in'] self.principal_name = authorizer_info['principal_name'] self.nick_name = authorizer_info['nick_name'] self.head_img = authorizer_info['head_img'] self.qrcode_url = authorizer_info['qrcode_url'] self.is_authorize = True self.agent = agent self.save() def uploadCode(self, template_id, user_version, user_desc): WeChat.commitCode(self.getAccessToken2(), template_id, user_version, user_desc) result = WeChat.submitAuditCode(self.getAccessToken2()) self.auditid = result['auditid'] self.wait_audit_version = user_version self.wait_audit_template = template_id self.audit_status = WechatApplet.AUDITING self.reject_reason = '' self.save() def refreshAuditStatus(self): result = WeChat.getLastSubmitAuditCodeStatus(self.getAccessToken2()) if self.auditid == str(result['auditid']): if result['status'] == WechatApplet.AUDIT_SUCCESS: self.weapp_audit_success() elif result['status'] == WechatApplet.AUDIT_REJECT: self.weapp_audit_fail(result['reason']) elif result['status'] == WechatApplet.RECALL: self.weapp_audit_recall() elif result['status'] == WechatApplet.AUDIT_DELAY: self.weapp_audit_delay(result['reason']) def weapp_audit_recall(self): self.auditid = '' self.wait_audit_template = None self.wait_audit_version = None self.audit_status = None self.reject_reason = '' self.save() def weapp_audit_success(self): self.user_version = self.wait_audit_version self.template_id = self.wait_audit_template self.auditid = '' self.wait_audit_template = None self.wait_audit_version = None self.audit_status = None self.reject_reason = '' self.save() def weapp_audit_fail(self, reason): self.audit_status = WechatApplet.AUDIT_REJECT self.reject_reason = reason self.save() def weapp_audit_delay(self, reason): self.audit_status = WechatApplet.AUDIT_DELAY self.reject_reason = reason self.save() def setDomain(self): requestdomain = uploaddomain = downloaddomain = ['https://print.zzliaoyuan.com', ] wsrequestdomain = [] WeChat.modify_domain(self.getAccessToken2(), 'set', requestdomain, wsrequestdomain, uploaddomain, downloaddomain) def addPlugin(self): result = WeChat.addPlugin(self.getAccessToken2()) return result def releaseApplet(self): result = WeChat.releaseCode(self.getAccessToken2()) return result def getMsgTemplateId(self, title): templates = WeChat.getTemplateList(self.getAccessToken()) for template in templates: if template['title'] == title: return template['priTmplId'] return '' def sendCreateOrderMsg(self, openid, msg_data, value=0): template_id = self.getMsgTemplateId('订单状态通知') if not template_id: return data = { 'character_string1': {'value': msg_data['no']}, 'date3':{'value':msg_data['create_time'].strftime('%Y-%m-%d %H:%M:%S')}, 'phrase2':{'value':msg_data['status']}, 'thing4':{'value': msg_data['commoditys']}, 'thing8':{'value': msg_data['tips']}, } page = 'pages/order/order?value={}'.format(value) WeChat.sendSubscribeMessage(self.getAccessToken(), openid, template_id, page, data) def sendConfirmOrderMsg(self, openid, msg_data): template_id = self.getMsgTemplateId('订单确认通知') if not template_id: return data = { 'character_string1': {'value': msg_data['no']}, 'time2':{'value':msg_data['create_time'].strftime('%Y-%m-%d %H:%M:%S')}, 'thing3':{'value':msg_data['commoditys']}, 'thing4':{'value': msg_data['address']}, 'thing5':{'value': msg_data['tips']}, } page = 'pages/order/order?value=2' WeChat.sendSubscribeMessage(self.getAccessToken(), openid, template_id, page, data) def sendSubmitLogisicsMsg(self, openid, msg_data): template_id = self.getMsgTemplateId('订单发货通知') if not template_id: return data = { 'character_string8': {'value': msg_data['no']}, 'time2':{'value':msg_data['dispatch_time']}, 'character_string4':{'value':msg_data['logistics_no']}, 'thing9':{'value': msg_data['logistics_company']}, 'thing12':{'value': msg_data['address']}, } page = 'pages/order/order?value=3' WeChat.sendSubscribeMessage(self.getAccessToken(), openid, template_id, page, data) def sendPayOrderMsg(self, openid, msg_data): template_id = self.getMsgTemplateId('订单支付成功通知') if not template_id: return data = { 'date3':{'value':msg_data['pay_time'].strftime('%Y-%m-%d %H:%M:%S')}, 'phrase4': {'value': msg_data['payment']}, 'character_string5': {'value': msg_data['no']}, 'amount2':{'value': msg_data['pay_amount']}, 'thing7':{'value': msg_data['tips']}, } page = 'pages/order/order?value=1' WeChat.sendSubscribeMessage(self.getAccessToken(), openid, template_id, page, data) def upload_cert_file(self, file): path = 'zzly_xcx_cert/%d/' % self.id upload_path = CertPath(path) filename = '%s%s' % (upload_path.path, file.name) full_filename = "%s/%s" % (settings.MEDIA_ROOT, filename) with open(full_filename, 'wb+') as destination: for chunk in file.chunks(): destination.write(chunk) if file.name == 'apiclient_cert.pem': self.apiclient_cert = full_filename elif file.name == 'apiclient_key.pem': self.apiclient_key = full_filename self.save() def getWXAppCode(self, param): page = 'pages/index/index' filename = WeChat.getWXAppCode(self.getAccessToken2(), page, param) return filename class MessageTemplate(models.Model): CREATE_ORDER = 1 PAY_ORDER = 2 CONFIRM_ORDER = 3 DELIVER = 4 TYPE_CHOICE = ( (CREATE_ORDER, u'用户下单'), (PAY_ORDER, u'支付成功'), (CONFIRM_ORDER, u'确认订单'), (DELIVER, u'发货通知'), ) wechat_app = models.ForeignKey(WechatApplet, verbose_name=u'小程序', on_delete=models.PROTECT) type = models.IntegerField(choices=TYPE_CHOICE, verbose_name=u'模板类别', null=True) template = models.CharField(max_length=60, verbose_name=u'模板ID', default="") class Meta: db_table = "wechat_message_temp" ordering = ['-id'] index_together = () verbose_name = u"小程序消息模板" default_permissions = () @staticmethod def get_temp_list(wechat_app): rows = MessageTemplate.objects.filter(wechat_app=wechat_app).exclude(template='').values_list('template', flat=True) return rows