models.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. # coding=utf-8
  2. import time
  3. import os
  4. from django.conf import settings
  5. from django.db import models
  6. from django.utils import timezone
  7. from apps.WechatTp.models import WechatTp
  8. from utils.wx.wechat import WeChat
  9. from utils.exceptions import CustomError
  10. from utils.file_operation import CertPath
  11. class WechatApplet(models.Model):
  12. AUDIT_SUCCESS = 0
  13. AUDIT_REJECT = 1
  14. AUDITING = 2
  15. RECALL = 3
  16. AUDIT_DELAY = 4
  17. AUDIT_STATUS_CHOICE = (
  18. (AUDIT_SUCCESS, u'审核通过'),
  19. (AUDIT_REJECT, u'审核拒绝'),
  20. (AUDITING, u'审核中'),
  21. (RECALL, u'已撤回'),
  22. (AUDIT_DELAY, u'审核延后'),
  23. )
  24. # agent = models.ForeignKey(Agent, verbose_name=u'代理商', on_delete=models.PROTECT, null=True, editable=False)
  25. wechat_tp = models.ForeignKey(WechatTp, verbose_name=u'第三方平台', on_delete=models.PROTECT, editable=False)
  26. authorizer_appid = models.CharField(max_length=512, verbose_name=u'授权方appid')
  27. secret = models.CharField(max_length=512, verbose_name=u'小程序秘钥', null=True)
  28. authorizer_refresh_token = models.CharField(max_length=512, verbose_name=u'刷新令牌')
  29. authorizer_access_token = models.CharField(max_length=512, verbose_name=u'令牌')
  30. access_token_gtime = models.DateTimeField(verbose_name=u"获取令牌时间")
  31. expires_in = models.IntegerField(verbose_name=u'令牌有效期')
  32. is_authorize = models.BooleanField(verbose_name=u'是否授权', default=False)
  33. message_template_id = models.CharField(max_length=255, verbose_name=u'消息模版ID', null=True)
  34. nick_name = models.CharField(max_length=255, verbose_name=u'昵称', default="")
  35. head_img = models.CharField(max_length=255, verbose_name=u'头像', default="")
  36. principal_name = models.CharField(max_length=255, verbose_name=u'主体名称', default="")
  37. qrcode_url = models.CharField(max_length=512, verbose_name=u'二维码', default="")
  38. user_version = models.CharField(max_length=512, verbose_name=u'当前程序版本', default="")
  39. template_id = models.CharField(max_length=512, verbose_name=u'当前模板', default="")
  40. agent_num = models.CharField(max_length=512, verbose_name=u'商户号', default="")
  41. agent_key = models.CharField(max_length=512, verbose_name=u'商户密钥', default="")
  42. apiclient_cert = models.CharField(max_length=255, verbose_name=u'API证书cert', default="")
  43. apiclient_key = models.CharField(max_length=255, verbose_name=u'API证书key', default="")
  44. auditid = models.CharField(max_length=512, verbose_name=u'待审核ID', default="")
  45. wait_audit_version = models.CharField(max_length=512, verbose_name=u'待审核版本', null=True)
  46. wait_audit_template = models.CharField(max_length=512, verbose_name=u'待审核模板', null=True)
  47. audit_status = models.IntegerField(choices=AUDIT_STATUS_CHOICE, verbose_name=u'审核状态', null=True)
  48. reject_reason = models.CharField(max_length=512, verbose_name=u'拒绝原因', default="")
  49. is_admin = models.BooleanField(verbose_name=u'是管理者小程序', default=False) # 河南全品书城管理系统的小程序属于管理者小程序,其他是代理商小程序
  50. class Meta:
  51. db_table = "wechat_applet"
  52. ordering = ['-id']
  53. index_together = ()
  54. verbose_name = u"代理商小程序"
  55. default_permissions = ()
  56. permissions = [
  57. ('manage_wechat_applet', u'管理'),
  58. ]
  59. @staticmethod
  60. def getById(id):
  61. try:
  62. id = int(id)
  63. except:
  64. raise CustomError(u'无效的小程序ID!')
  65. instance = WechatApplet.objects.filter(pk=id).first()
  66. if not instance:
  67. raise CustomError(u'未找到相应的小程序!')
  68. return instance
  69. @staticmethod
  70. def getByAppid(appid):
  71. instance = WechatApplet.objects.filter(authorizer_appid=appid, is_authorize=True).first()
  72. if not instance:
  73. raise CustomError(u'未找到相应的小程序!')
  74. return instance
  75. @staticmethod
  76. def addAuthorizer(wechat_component, authorization_code, agent):
  77. gtime = timezone.now()
  78. component_appid = wechat_component.getAppid()
  79. component_access_token = wechat_component.getAccessToken()
  80. res = WeChat.getAuthorizationInfo(component_appid, authorization_code, component_access_token)
  81. ares = WeChat.getAuthorizerInfo(component_appid, res['authorization_info']['authorizer_appid'], component_access_token)
  82. authorizer = WechatApplet.getByAppidAndComponentAppid(res['authorization_info']['authorizer_appid'], component_appid)
  83. if authorizer:
  84. if authorizer.is_authorize:
  85. raise CustomError(u'该小程序已授权!')
  86. authorizer.refresh(res['authorization_info'], ares['authorizer_info'], gtime, agent)
  87. else:
  88. authorizer = WechatApplet.objects.create(
  89. agent=agent,
  90. wechat_tp=wechat_component,
  91. authorizer_appid=res['authorization_info']['authorizer_appid'],
  92. authorizer_refresh_token=res['authorization_info']['authorizer_refresh_token'],
  93. authorizer_access_token=res['authorization_info']['authorizer_access_token'],
  94. access_token_gtime=gtime,
  95. expires_in=res['authorization_info']['expires_in'],
  96. principal_name=ares['authorizer_info']['principal_name'],
  97. nick_name=ares['authorizer_info']['nick_name'],
  98. head_img=ares['authorizer_info']['head_img'],
  99. qrcode_url=ares['authorizer_info']['qrcode_url'],
  100. is_authorize=True
  101. )
  102. # 设置服务器域名
  103. authorizer.setDomain()
  104. return authorizer
  105. @staticmethod
  106. def getByAppidAndComponentAppid(appid, component_appid):
  107. authorizer = WechatApplet.objects.filter(authorizer_appid=appid, wechat_tp__component_appid=component_appid).first()
  108. return authorizer
  109. def getComponent(self):
  110. return self.wechat_tp
  111. def getAccessToken(self):
  112. if self.authorizer_access_token:
  113. last_time = time.mktime(self.access_token_gtime.timetuple()) + self.expires_in
  114. now = time.mktime(timezone.now().timetuple())
  115. if last_time > now:
  116. return self.authorizer_access_token
  117. gtime = timezone.now()
  118. res = WeChat.getAccessToken(self.authorizer_appid, self.secret)
  119. self.refreshAccessToken(gtime, res['access_token'], res['expires_in'])
  120. return self.authorizer_access_token
  121. def getAccessToken2(self):
  122. # 绑定第三方平台小程序,获取token
  123. if self.authorizer_access_token:
  124. last_time = time.mktime(self.access_token_gtime.timetuple()) + self.expires_in
  125. now = time.mktime(timezone.now().timetuple())
  126. if last_time > now:
  127. return self.authorizer_access_token
  128. if not self.authorizer_refresh_token:
  129. return ''
  130. gtime = timezone.now()
  131. component = self.getComponent()
  132. res = WeChat.getAuthorizerAccessToken(component.getAppid(), self.authorizer_appid, self.authorizer_refresh_token, component.getAccessToken())
  133. self.refreshAccessToken(gtime, res['authorizer_access_token'], res['expires_in'], res['authorizer_refresh_token'])
  134. return self.authorizer_access_token
  135. def revoke(self):
  136. agent = self.agent
  137. agent.is_bind_app = False
  138. agent.save()
  139. self.is_authorize = False
  140. self.save()
  141. def refreshAccessToken(self, gtime, access_token, expires_in, refresh_token=''):
  142. self.authorizer_access_token = access_token
  143. self.access_token_gtime = gtime
  144. self.expires_in = expires_in
  145. self.authorizer_refresh_token = refresh_token
  146. self.save()
  147. def refresh(self, authorization_info, authorizer_info, access_token_gtime, agent):
  148. self.authorizer_refresh_token = authorization_info['authorizer_refresh_token']
  149. self.authorizer_access_token = authorization_info['authorizer_access_token']
  150. self.access_token_gtime = access_token_gtime
  151. self.expires_in = authorization_info['expires_in']
  152. self.principal_name = authorizer_info['principal_name']
  153. self.nick_name = authorizer_info['nick_name']
  154. self.head_img = authorizer_info['head_img']
  155. self.qrcode_url = authorizer_info['qrcode_url']
  156. self.is_authorize = True
  157. self.agent = agent
  158. self.save()
  159. def uploadCode(self, template_id, user_version, user_desc):
  160. WeChat.commitCode(self.getAccessToken2(), template_id, user_version, user_desc)
  161. result = WeChat.submitAuditCode(self.getAccessToken2())
  162. self.auditid = result['auditid']
  163. self.wait_audit_version = user_version
  164. self.wait_audit_template = template_id
  165. self.audit_status = WechatApplet.AUDITING
  166. self.reject_reason = ''
  167. self.save()
  168. def refreshAuditStatus(self):
  169. result = WeChat.getLastSubmitAuditCodeStatus(self.getAccessToken2())
  170. if self.auditid == str(result['auditid']):
  171. if result['status'] == WechatApplet.AUDIT_SUCCESS:
  172. self.weapp_audit_success()
  173. elif result['status'] == WechatApplet.AUDIT_REJECT:
  174. self.weapp_audit_fail(result['reason'])
  175. elif result['status'] == WechatApplet.RECALL:
  176. self.weapp_audit_recall()
  177. elif result['status'] == WechatApplet.AUDIT_DELAY:
  178. self.weapp_audit_delay(result['reason'])
  179. def weapp_audit_recall(self):
  180. self.auditid = ''
  181. self.wait_audit_template = None
  182. self.wait_audit_version = None
  183. self.audit_status = None
  184. self.reject_reason = ''
  185. self.save()
  186. def weapp_audit_success(self):
  187. self.user_version = self.wait_audit_version
  188. self.template_id = self.wait_audit_template
  189. self.auditid = ''
  190. self.wait_audit_template = None
  191. self.wait_audit_version = None
  192. self.audit_status = None
  193. self.reject_reason = ''
  194. self.save()
  195. def weapp_audit_fail(self, reason):
  196. self.audit_status = WechatApplet.AUDIT_REJECT
  197. self.reject_reason = reason
  198. self.save()
  199. def weapp_audit_delay(self, reason):
  200. self.audit_status = WechatApplet.AUDIT_DELAY
  201. self.reject_reason = reason
  202. self.save()
  203. def setDomain(self):
  204. requestdomain = uploaddomain = downloaddomain = [settings.SERVER_DOMAIN, ]
  205. wsrequestdomain = []
  206. WeChat.modify_domain(self.getAccessToken2(), 'set', requestdomain, wsrequestdomain, uploaddomain, downloaddomain)
  207. def addPlugin(self):
  208. result = WeChat.addPlugin(self.getAccessToken2())
  209. return result
  210. def releaseApplet(self):
  211. result = WeChat.releaseCode(self.getAccessToken2())
  212. return result
  213. def getMsgTemplateId(self, title):
  214. templates = WeChat.getTemplateList(self.getAccessToken())
  215. for template in templates:
  216. if template['title'] == title:
  217. return template['priTmplId']
  218. return ''
  219. def sendCreateOrderMsg(self, openid, msg_data, value=0):
  220. template_id = self.getMsgTemplateId('订单状态通知')
  221. if not template_id:
  222. return
  223. data = {
  224. 'character_string1': {'value': msg_data['no']},
  225. 'date3':{'value':msg_data['create_time'].strftime('%Y-%m-%d %H:%M:%S')},
  226. 'phrase2':{'value':msg_data['status']},
  227. 'thing4':{'value': msg_data['commoditys']},
  228. 'thing8':{'value': msg_data['tips']},
  229. }
  230. page = 'pages/order/order?value={}'.format(value)
  231. WeChat.sendSubscribeMessage(self.getAccessToken(), openid, template_id, page, data)
  232. def sendConfirmOrderMsg(self, openid, msg_data):
  233. template_id = self.getMsgTemplateId('订单确认通知')
  234. if not template_id:
  235. return
  236. data = {
  237. 'character_string1': {'value': msg_data['no']},
  238. 'time2':{'value':msg_data['create_time'].strftime('%Y-%m-%d %H:%M:%S')},
  239. 'thing3':{'value':msg_data['commoditys']},
  240. 'thing4':{'value': msg_data['address']},
  241. 'thing5':{'value': msg_data['tips']},
  242. }
  243. page = 'pages/order/order?value=2'
  244. WeChat.sendSubscribeMessage(self.getAccessToken(), openid, template_id, page, data)
  245. def sendSubmitLogisicsMsg(self, openid, msg_data):
  246. template_id = self.getMsgTemplateId('订单发货通知')
  247. if not template_id:
  248. return
  249. data = {
  250. 'character_string8': {'value': msg_data['no']},
  251. 'time2':{'value':msg_data['dispatch_time']},
  252. 'character_string4':{'value':msg_data['logistics_no']},
  253. 'thing9':{'value': msg_data['logistics_company']},
  254. 'thing12':{'value': msg_data['address']},
  255. }
  256. page = 'pages/order/order?value=3'
  257. WeChat.sendSubscribeMessage(self.getAccessToken(), openid, template_id, page, data)
  258. def sendPayOrderMsg(self, openid, msg_data):
  259. template_id = self.getMsgTemplateId('订单支付成功通知')
  260. if not template_id:
  261. return
  262. data = {
  263. 'date3':{'value':msg_data['pay_time'].strftime('%Y-%m-%d %H:%M:%S')},
  264. 'phrase4': {'value': msg_data['payment']},
  265. 'character_string5': {'value': msg_data['no']},
  266. 'amount2':{'value': msg_data['pay_amount']},
  267. 'thing7':{'value': msg_data['tips']},
  268. }
  269. page = 'pages/order/order?value=1'
  270. WeChat.sendSubscribeMessage(self.getAccessToken(), openid, template_id, page, data)
  271. def upload_cert_file(self, file):
  272. path = 'zzly_xcx_cert/%d/' % self.id
  273. upload_path = CertPath(path)
  274. filename = '%s%s' % (upload_path.path, file.name)
  275. full_filename = "%s/%s" % (settings.MEDIA_ROOT, filename)
  276. with open(full_filename, 'wb+') as destination:
  277. for chunk in file.chunks():
  278. destination.write(chunk)
  279. if file.name == 'apiclient_cert.pem':
  280. self.apiclient_cert = full_filename
  281. elif file.name == 'apiclient_key.pem':
  282. self.apiclient_key = full_filename
  283. self.save()
  284. def getWXAppCode(self, param):
  285. page = 'pages/index/index'
  286. filename = WeChat.getWXAppCode(self.getAccessToken2(), page, param)
  287. return filename
  288. class MessageTemplate(models.Model):
  289. CREATE_ORDER = 1
  290. PAY_ORDER = 2
  291. CONFIRM_ORDER = 3
  292. DELIVER = 4
  293. TYPE_CHOICE = (
  294. (CREATE_ORDER, u'用户下单'),
  295. (PAY_ORDER, u'支付成功'),
  296. (CONFIRM_ORDER, u'确认订单'),
  297. (DELIVER, u'发货通知'),
  298. )
  299. wechat_app = models.ForeignKey(WechatApplet, verbose_name=u'小程序', on_delete=models.PROTECT)
  300. type = models.IntegerField(choices=TYPE_CHOICE, verbose_name=u'模板类别', null=True)
  301. template = models.CharField(max_length=60, verbose_name=u'模板ID', default="")
  302. class Meta:
  303. db_table = "wechat_message_temp"
  304. ordering = ['-id']
  305. index_together = ()
  306. verbose_name = u"小程序消息模板"
  307. default_permissions = ()
  308. @staticmethod
  309. def get_temp_list(wechat_app):
  310. rows = MessageTemplate.objects.filter(wechat_app=wechat_app).exclude(template='').values_list('template', flat=True)
  311. return rows