AiController.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879
  1. import logging
  2. import time
  3. from urllib.parse import quote, parse_qs, unquote
  4. import paypalrestsdk
  5. from django.db import transaction
  6. from django.db.models import Q, F, Sum
  7. from django.http import HttpResponseRedirect, HttpResponse
  8. from django.views.generic.base import View
  9. from Ansjer.config import PAYPAL_CRD, SERVER_DOMAIN_SSL, DETECT_PUSH_DOMAINS, LOGGER
  10. from Model.models import Device_Info, Order_Model, ExperienceAiModel, Pay_Type, CDKcontextModel, UidPushModel, \
  11. AiStoreMeal, AiService, UidSetModel
  12. from Object.AliPayObject import AliPayObject
  13. from Object.ETkObject import ETkObject
  14. from Object.RedisObject import RedisObject
  15. from Object.ResponseObject import ResponseObject
  16. from Object.TokenObject import TokenObject
  17. from Object.WechatPayObject import WechatPayObject
  18. from Service.CommonService import CommonService
  19. class AiView(View):
  20. """
  21. AI业务功能
  22. AI套餐,开关,消息列表
  23. """
  24. def get(self, request, *args, **kwargs):
  25. request.encoding = 'utf-8'
  26. operation = kwargs.get('operation')
  27. return self.validation(request.GET, request, operation)
  28. def post(self, request, *args, **kwargs):
  29. request.encoding = 'utf-8'
  30. operation = kwargs.get('operation')
  31. return self.validation(request.POST, request, operation)
  32. def validation(self, request_dict, request, operation):
  33. response = ResponseObject()
  34. if operation is None:
  35. return response.json(414)
  36. # 支付回调接口
  37. elif operation == 'doPayPalCallBack': # paypal支付回调
  38. return self.do_paypal_callback(request_dict, response)
  39. elif operation == 'doAlipayCallBack': # 支付宝支付回调
  40. return self.do_alipay_callback(request_dict, response)
  41. elif operation == 'doWechatCallBack': # 微信支付回调
  42. return self.do_wechat_callback(request, response)
  43. else:
  44. token = request_dict.get('token', None)
  45. tko = TokenObject(token)
  46. response.lang = tko.lang
  47. if tko.code != 0:
  48. return response.json(tko.code)
  49. user_id = tko.userID
  50. # 套餐相关接口
  51. if operation == 'commoditylist': # 查询套餐列表
  52. return self.commodity_list(request_dict, response)
  53. # elif operation == 'experienceOrder': # 体验套餐
  54. # return self.experience_order(request_dict, user_id, response)
  55. # elif operation == 'createpayorder': # 创建支付订单
  56. # return self.create_pay_order(request_dict, request, user_id, response)
  57. elif operation == 'queryorderlist': # 查询订单列表
  58. return self.query_order_list(request_dict, user_id, response)
  59. elif operation == 'getUsingPackage': # 获取当前使用套餐
  60. return self.get_using_package(request_dict, response)
  61. # 开关相关接口
  62. elif operation == 'getAiStatus': # 获取开关状态
  63. return self.get_ai_status(request_dict, response)
  64. elif operation == 'changeaistatus': # 修改开关状态
  65. return self.change_ai_status(request_dict, user_id, response)
  66. else:
  67. return response.json(414)
  68. @staticmethod
  69. def commodity_list(request_dict, response):
  70. """
  71. 查询套餐列表
  72. @param request_dict: 请求数据
  73. @request_dict uid: uid
  74. @request_dict lang: 语言
  75. @param response: 响应
  76. @return: response
  77. """
  78. uid = request_dict.get('uid', None)
  79. lang = request_dict.get('lang', 'en')
  80. try:
  81. # DVR/NVR设备暂不返回套餐列表
  82. device_info_qs = Device_Info.objects.filter(Q(UID=uid), Q(Type__lte=4) | Q(Type=10001))
  83. if device_info_qs.exists():
  84. return response.json(0)
  85. # 没体验过的设备只返回体验套餐,体验过的不返回体验套餐
  86. exc_ai_qs = ExperienceAiModel.objects.filter(uid=uid, experience_type=0)
  87. if exc_ai_qs.exists():
  88. ai_meal_qs = AiStoreMeal.objects.filter(~Q(pay_type=10))
  89. else:
  90. ai_meal_qs = AiStoreMeal.objects.filter(pay_type=10)
  91. # 查询套餐数据
  92. ai_meal_qs = ai_meal_qs.filter(is_show=1, lang__lang=lang). \
  93. annotate(ai_meal_id=F('id'), title=F('lang__title'), content=F('lang__content')). \
  94. values('ai_meal_id', 'title', 'content', 'price', 'effective_day', 'currency', 'virtual_price',
  95. 'symbol', 'is_beta')
  96. if not ai_meal_qs.exists():
  97. return response.json(0)
  98. # 查询每种套餐的所有支付方式
  99. ai_meal_list = list(ai_meal_qs)
  100. for ai_meal in ai_meal_list:
  101. pay_type_qs = Pay_Type.objects.filter(aistoremeal=ai_meal['ai_meal_id']).values('id', 'payment')
  102. ai_meal['pay_type'] = list(pay_type_qs)
  103. result = {
  104. 'meals': ai_meal_list,
  105. }
  106. return response.json(0, result)
  107. except Exception as e:
  108. return response.json(500, repr(e))
  109. @staticmethod
  110. def experience_order(request_dict, user_id, response):
  111. """
  112. 体验套餐
  113. @param request_dict: 请求数据
  114. @request_dict uid: uid
  115. @request_dict channel: 通道
  116. @request_dict pay_type: 支付类型
  117. @request_dict rank: 套餐id
  118. @request_dict cdk: 兑换码
  119. @request_dict lang: 语言
  120. @param user_id: 用户id
  121. @param response: 响应
  122. @return: response
  123. """
  124. logger = logging.getLogger('info')
  125. uid = request_dict.get('uid', None)
  126. channel = request_dict.get('channel', None)
  127. pay_type = int(request_dict.get('pay_type', 10))
  128. rank = request_dict.get('rank', None)
  129. cdk = request_dict.get('cdk', None)
  130. lang = request_dict.get('lang', 'en')
  131. # 使用redis设置唯一key加锁
  132. redisObj = RedisObject()
  133. redis_key = uid + 'do_experience_ai_order'
  134. isLock = redisObj.CONN.setnx(redis_key, 1)
  135. if not isLock:
  136. return response.json(5)
  137. redisObj.CONN.expire(redis_key, 60)
  138. try:
  139. if pay_type == 10: # 判断是否已体验过套餐
  140. exc_ai_qs = ExperienceAiModel.objects.filter(uid=uid, experience_type=0)
  141. if exc_ai_qs.exists():
  142. return response.json(5)
  143. if cdk is not None and pay_type == 11: # 兑换码体验
  144. cdk_qs = CDKcontextModel.objects.filter(cdk=cdk).values('is_activate', 'rank__id',
  145. 'rank__commodity_code')
  146. if not cdk_qs.exists():
  147. return response.json(10040)
  148. if cdk_qs[0]['is_activate'] == 1:
  149. return response.json(10039)
  150. rank = cdk_qs[0]['rank__id']
  151. if not all([uid, channel, rank]):
  152. redisObj.del_data(key=redis_key)
  153. return response.json(444)
  154. # 判断是否为主用户操作
  155. device_info_qs = Device_Info.objects.filter(Q(UID=uid) & ~Q(vodPrimaryUserID='')).values('vodPrimaryUserID')
  156. if device_info_qs.exists():
  157. if device_info_qs[0]['vodPrimaryUserID'] != user_id:
  158. if pay_type == 10:
  159. return response.json(10035)
  160. if pay_type == 11:
  161. return response.json(10036)
  162. dv_qs = Device_Info.objects.filter(userID_id=user_id, UID=uid, isShare=False, isExist=1)
  163. if not dv_qs.exists():
  164. return response.json(12)
  165. orderID = CommonService.createOrderID()
  166. nowTime = int(time.time())
  167. ai_store_meal_qs = AiStoreMeal.objects.filter(id=rank, lang__lang=lang, is_show=1). \
  168. values('lang__content', 'price', 'currency', 'effective_day')
  169. if not ai_store_meal_qs.exists():
  170. return response.json(173)
  171. effective_day = ai_store_meal_qs[0]['effective_day']
  172. endTime = int(time.time()) + effective_day * 24 * 60 * 60 # 套餐结束时间
  173. # 查询中文套餐名
  174. ai_cn_store_meal_qs = AiStoreMeal.objects.filter(id=rank, lang__lang='cn', is_show=1). \
  175. values('lang__content', 'lang__title')
  176. if ai_cn_store_meal_qs.exists():
  177. store_meal_name = ai_cn_store_meal_qs[0]['lang__title'] + '-' + ai_cn_store_meal_qs[0]['lang__content']
  178. else:
  179. store_meal_name = '未知套餐'
  180. with transaction.atomic():
  181. # 订单表创建数据
  182. Order_Model.objects.create(orderID=orderID, UID=uid, channel=channel, userID_id=user_id,
  183. desc=ai_store_meal_qs[0]['lang__content'], payType=pay_type, payTime=nowTime,
  184. price=ai_store_meal_qs[0]['price'], currency=ai_store_meal_qs[0]['currency'],
  185. addTime=nowTime, updTime=nowTime, pay_url='AI体验',
  186. store_meal_name=store_meal_name, order_type=1,
  187. rank_id=1, ai_rank_id=rank, status=1)
  188. # ai服务表创建数据
  189. AiService.objects.create(uid=uid, channel=channel, orders_id=orderID, detect_status=1, endTime=endTime,
  190. addTime=nowTime, updTime=nowTime, use_status=1)
  191. logger.info('{}成功开通AI体验,结束时间{}'.format(uid, endTime))
  192. if pay_type == 10:
  193. ExperienceAiModel.objects.create(
  194. experience_type=0,
  195. uid=uid,
  196. do_time=nowTime
  197. )
  198. elif pay_type == 11:
  199. CDKcontextModel.objects.filter(cdk=cdk).update(is_activate=1, order=orderID)
  200. redisObj.del_data(key=redis_key)
  201. pay_ok_url = "{}cloudstorage/payOK?paytype={}&lang={}".format(SERVER_DOMAIN_SSL, pay_type, lang)
  202. return response.json(0, pay_ok_url)
  203. except Exception as e:
  204. print(e)
  205. redisObj.del_data(key=redis_key)
  206. return response.json(474)
  207. @classmethod
  208. def create_pay_order(cls, request_dict, request, user_id, response):
  209. """
  210. 创建支付订单
  211. @param request_dict: 请求数据
  212. @param request: 请求体
  213. @request_dict uid: uid
  214. @request_dict channel: 通道
  215. @request_dict pay_type: 支付类型
  216. @request_dict rank: 套餐id
  217. @request_dict lang: 语言
  218. @param user_id: 用户id
  219. @param response: 响应
  220. @return: response
  221. """
  222. uid = request_dict.get('uid', None)
  223. channel = request_dict.get('channel', None)
  224. pay_type = int(request_dict.get('pay_type', 1))
  225. rank = request_dict.get('rank', None)
  226. lang = request_dict.get('lang', 'en')
  227. if not all([uid, channel, rank]):
  228. return response.json(444)
  229. try:
  230. # 获取ai套餐数据
  231. ai_sm_qs = AiStoreMeal.objects.filter(id=rank, pay_type=pay_type, is_show=1, lang__lang=lang). \
  232. values('lang__title', 'lang__content', 'currency', 'price')
  233. if not ai_sm_qs.exists():
  234. return response.json(173)
  235. title = ai_sm_qs[0]['lang__title']
  236. content = ai_sm_qs[0]['lang__content']
  237. currency = ai_sm_qs[0]['currency']
  238. price = ai_sm_qs[0]['price']
  239. # 查询中文套餐名
  240. ai_store_meal_qs = AiStoreMeal.objects.filter(id=rank, is_show=1, lang__lang='cn'). \
  241. values('lang__title', 'lang__content')
  242. if ai_store_meal_qs.exists():
  243. store_meal_name = ai_store_meal_qs[0]['lang__title'] + '-' + ai_store_meal_qs[0]['lang__content']
  244. else:
  245. store_meal_name = '未知套餐'
  246. now_time = int(time.time())
  247. price = round(float(price), 2)
  248. order_id = CommonService.createOrderID()
  249. order_dict = {
  250. 'orderID': order_id,
  251. 'UID': uid,
  252. 'channel': channel,
  253. 'userID_id': user_id,
  254. 'desc': content,
  255. 'payType': pay_type,
  256. 'payTime': now_time,
  257. 'price': price,
  258. 'currency': currency,
  259. 'addTime': now_time,
  260. 'updTime': now_time,
  261. 'ai_rank_id': rank,
  262. 'rank_id': 1,
  263. 'order_type': 1,
  264. 'store_meal_name': store_meal_name
  265. }
  266. # 创建订单数据和返回支付回调链接
  267. if pay_type == 1: # PayPal支付
  268. res_dict = cls.create_paypal_payment(lang, order_id, price, currency, content)
  269. if not res_dict:
  270. return response.json(10, 'create ai order failed')
  271. order_dict['paymentID'], order_dict['pay_url'] = res_dict['payment_id'], res_dict['pay_url']
  272. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url']}
  273. elif pay_type == 2: # 支付宝支付
  274. res_dict = cls.create_alipay_payment(lang, order_id, price, title, content)
  275. if not res_dict:
  276. return response.json(10, 'create ai order failed')
  277. order_dict['pay_url'] = res_dict['pay_url']
  278. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url']}
  279. elif pay_type == 3: # 微信支付
  280. ip = CommonService.get_ip_address(request)
  281. res_dict = cls.create_wechat_payment(lang, order_id, price, ip, content)
  282. if not res_dict:
  283. return response.json(10, 'create ai order failed')
  284. order_dict['pay_url'], sign_params = res_dict['pay_url'], res_dict['sign_params']
  285. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url'], 'result': sign_params}
  286. else:
  287. return response.json(444, {'param': 'pay_type'})
  288. Order_Model.objects.create(**order_dict)
  289. return response.json(0, res_data)
  290. except Exception as e:
  291. return response.json(500, repr(e))
  292. @staticmethod
  293. def query_order_list(request_dict, user_id, response):
  294. """
  295. 查询订单列表
  296. @param request_dict: 请求数据
  297. @param user_id: 用户id
  298. @request_dict page: 页数
  299. @request_dict line: 条数
  300. @request_dict uid: uid
  301. @request_dict lang: 语言
  302. @param response: 响应
  303. @return: response
  304. """
  305. page = request_dict.get('page', None)
  306. line = request_dict.get('line', None)
  307. uid = request_dict.get('uid', None)
  308. lang = request_dict.get('lang', 'en')
  309. if not all([page, line]):
  310. return response.json(444, 'page,line')
  311. page, line = int(page), int(line)
  312. try:
  313. order_qs = Order_Model.objects.filter(userID_id=user_id, status=1, order_type=1, ai_rank__lang__lang=lang)
  314. if uid: # 查询指定设备订单
  315. order_qs.filter(UID=uid)
  316. if not order_qs.exists():
  317. return response.json(173)
  318. count = order_qs.count()
  319. order_qs = order_qs.annotate(rank__title=F('ai_rank__lang__title'),
  320. rank__content=F('ai_rank__lang__content'),
  321. rank__day=F('ai_rank__effective_day'), rank__price=F('ai_rank__price'),
  322. rank__expire=F('ai_rank__effective_day'), rank__id=F('ai_rank_id'),
  323. rank__currency=F('ai_rank__currency'))
  324. order_qs = order_qs[(page - 1) * line:page * line].values('orderID', 'UID', 'channel', 'desc', 'price',
  325. 'currency', 'addTime', 'updTime', 'paypal',
  326. 'rank__day', 'payType', 'rank__price', 'status',
  327. 'rank__content', 'rank__title', 'rank__currency',
  328. 'rank__expire', 'ai_rank_id')
  329. order_list = list(order_qs)
  330. data = []
  331. now_time = int(time.time())
  332. uid_list = [order['UID'] for order in order_list]
  333. device_info_qs = Device_Info.objects.filter(userID_id=user_id, UID__in=uid_list).values('id', 'UID', 'Type')
  334. for order in order_list:
  335. if order['status'] == 0:
  336. if order['addTime'] + 3600 < now_time:
  337. order['status'] = 3
  338. for did in device_info_qs:
  339. if order['UID'] == did['UID']:
  340. order['did'] = did['id']
  341. order['Type'] = did['Type']
  342. data.append(order)
  343. return response.json(0, {'data': data, 'count': count})
  344. except Exception as e:
  345. return response.json(500, repr(e))
  346. @staticmethod
  347. def get_using_package(request_dict, response):
  348. """
  349. 获取当前使用套餐
  350. @param request_dict: 请求数据
  351. @request_dict uid: uid
  352. @request_dict lang: 语言
  353. @param response: 响应
  354. @return: response
  355. """
  356. uid = request_dict.get('uid', None)
  357. lang = request_dict.get('lang', 'en')
  358. if not uid:
  359. return response.json(444, 'uid')
  360. try:
  361. ai_service_qs = AiService.objects.filter(uid=uid, use_status=1, orders__ai_rank__lang__lang=lang)
  362. if not ai_service_qs.exists():
  363. return response.json(0, [])
  364. # 计算套餐过期时间
  365. sum_end_time = AiService.objects.filter(Q(uid=uid), ~Q(use_status=2)).aggregate(Sum('endTime'))[
  366. 'endTime__sum']
  367. ai_service_qs = ai_service_qs.order_by('addTime').annotate(
  368. bucket__content=F('orders__ai_rank__lang__title')). \
  369. values('uid', 'use_status', 'bucket__content')
  370. ai_service_data = ai_service_qs[0]
  371. ai_service_data['endTime'] = sum_end_time
  372. # 如果存在序列号返回完整序列号
  373. device_info_qs = Device_Info.objects.filter(UID=uid).values('serial_number', 'Type')
  374. serial_number = device_info_qs[0]['serial_number']
  375. device_type = device_info_qs[0]['Type']
  376. if serial_number:
  377. ai_service_data['serial_number'] = CommonService.get_full_serial_number(uid, serial_number, device_type)
  378. return response.json(0, [ai_service_data])
  379. except Exception as e:
  380. return response.json(500, repr(e))
  381. @staticmethod
  382. def get_ai_status(request_dict, response):
  383. """
  384. 获取AI开关状态
  385. @param request_dict: 请求数据
  386. @request_dict uid: uid
  387. @param response: 响应
  388. @return: response
  389. """
  390. uid = request_dict.get('uid', None)
  391. if not uid:
  392. return response.json(444)
  393. try:
  394. ai_server_qs = AiService.objects.filter(uid=uid, use_status=1).values('detect_status', 'detect_group')
  395. if not ai_server_qs.exists():
  396. return response.json(173)
  397. res = {
  398. 'detect_status': ai_server_qs[0]['detect_status'],
  399. 'detect_group': ai_server_qs[0]['detect_group'],
  400. }
  401. return response.json(0, {'data': res})
  402. except Exception as e:
  403. return response.json(500, repr(e))
  404. @staticmethod
  405. def change_ai_status(request_dict, user_id, response):
  406. """
  407. 修改AI开关状态
  408. @param request_dict: 请求数据
  409. @request_dict token_val: 设备验证令牌
  410. @request_dict appBundleId: app包id
  411. @request_dict app_type: app类型
  412. @request_dict push_type: 推送类型
  413. @request_dict status: 开关状态, 0: 关, 1: 开
  414. @request_dict m_code: 手机唯一标识
  415. @request_dict uid: uid
  416. @request_dict lang: 语言
  417. @request_dict tz: 时区
  418. @request_dict detect_group: 检测类型
  419. @request_dict interval: 推送间隔
  420. @request_dict domain_name: 域名
  421. @param user_id: 用户id
  422. @param response: 响应
  423. @return: response
  424. """
  425. token_val = request_dict.get('token_val', None)
  426. appBundleId = request_dict.get('appBundleId', None)
  427. app_type = request_dict.get('app_type', None)
  428. push_type = request_dict.get('push_type', None)
  429. status = request_dict.get('status', None)
  430. m_code = request_dict.get('m_code', None)
  431. uid = request_dict.get('uid', None)
  432. lang = request_dict.get('lang', 'en')
  433. tz = request_dict.get('tz', '0')
  434. detect_group = request_dict.get('detect_group', None)
  435. interval = request_dict.get('interval', None)
  436. domain_name = request_dict.get('domain_name', None)
  437. if not all([appBundleId, app_type, token_val, uid, m_code, status]):
  438. return response.json(444, 'appBundleId, app_type, token_val, uid,m_code, status')
  439. # 如果传空上来,就默认为0
  440. tz = '0' if tz == '' else tz.replace('GMT', '')
  441. try:
  442. ai_service_qs = AiService.objects.filter(uid=uid, use_status=1)
  443. if not ai_service_qs.exists():
  444. return response.json(10053)
  445. nowTime = int(time.time())
  446. endTime = ai_service_qs.values('endTime')[0]['endTime']
  447. if nowTime > endTime:
  448. return response.json(10054)
  449. # 查询设备是否属于该用户
  450. device_info_qs = Device_Info.objects.filter(userID_id=user_id, UID=uid)
  451. if not device_info_qs.exists():
  452. return response.json(14)
  453. status = int(status)
  454. nowTime = int(time.time())
  455. uid_set_qs = UidSetModel.objects.filter(uid=uid)
  456. if uid_set_qs.exists():
  457. uid_set_id = uid_set_qs[0].id
  458. interval = uid_set_qs[0].new_detect_interval if not interval else interval
  459. qs_data = {
  460. 'updTime': nowTime,
  461. }
  462. if interval:
  463. qs_data['detect_interval'] = int(interval)
  464. qs_data['detect_group'] = detect_group if detect_group else ''
  465. uid_set_qs.update(**qs_data)
  466. else:
  467. qs_data = {
  468. 'uid': uid,
  469. 'addTime': nowTime,
  470. 'updTime': nowTime,
  471. 'device_type': device_info_qs[0].Type
  472. }
  473. if interval:
  474. qs_data['detect_interval'] = int(interval)
  475. qs_data['detect_group'] = detect_group if detect_group else ''
  476. # 添加设备配置
  477. uid_set_qs = UidSetModel.objects.create(**qs_data)
  478. uid_set_id = uid_set_qs.id
  479. qs_data['detect_status'] = status # ai开关状态
  480. thing_name = CommonService.query_serial_with_uid(uid) # 存在序列号则为使用序列号作为物品名
  481. topic_name = 'ansjer/generic/{}'.format(thing_name)
  482. if status == 0: # 关闭
  483. # mqtt通知设备关闭AI识别功能
  484. msg = {'commandType': 'AIDisable'}
  485. req_success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
  486. if not req_success:
  487. return response.json(10044)
  488. ai_service_qs.update(**qs_data)
  489. return response.json(0)
  490. elif status == 1: # 开启
  491. # 更新或创建uid_push数据
  492. uid_push_qs = UidPushModel.objects.filter(userID_id=user_id, m_code=m_code, uid_set__uid=uid)
  493. uid_push_data = {
  494. 'appBundleId': appBundleId,
  495. 'app_type': app_type,
  496. 'push_type': push_type,
  497. 'token_val': token_val,
  498. 'updTime': nowTime,
  499. 'lang': lang,
  500. 'tz': tz
  501. }
  502. if uid_push_qs.exists():
  503. uid_push_qs.update(**uid_push_data)
  504. else:
  505. uid_push_data['uid_set_id'] = uid_set_id
  506. uid_push_data['userID_id'] = user_id
  507. uid_push_data['m_code'] = m_code
  508. uid_push_data['addTime'] = nowTime
  509. UidPushModel.objects.create(**uid_push_data)
  510. if appBundleId == 0 or appBundleId == '0':
  511. LOGGER.info('AiService/changeaistatus接口推送数据:{}'.format(request_dict))
  512. etkObj = ETkObject(etk='')
  513. etk = etkObj.encrypt(uid)
  514. # mqtt通知设备开启AI识别功能
  515. push_url = DETECT_PUSH_DOMAINS
  516. # 欧洲域名固定返回欧洲域名
  517. if domain_name in ['api.zositeche.com', 'api.loocam3.com', 'common.neutral3.com']:
  518. push_url = 'https://push.zositeche.com/'
  519. aiIdentificationUrl = '{}AiService/identification'.format(push_url)
  520. msg = {
  521. 'commandType': 'AIEnable',
  522. 'payload': {
  523. 'etk': etk,
  524. 'endTime': endTime,
  525. 'aiIdentificationUrl': aiIdentificationUrl,
  526. }
  527. }
  528. req_success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
  529. if not req_success:
  530. return response.json(10044)
  531. ai_service_qs.update(**qs_data)
  532. return response.json(0, {'aiIdentificationUrl': aiIdentificationUrl, 'endTime': endTime, 'etk': etk})
  533. except Exception as e:
  534. return response.json(500, repr(e))
  535. @staticmethod
  536. def create_paypal_payment(lang, order_id, price, currency, content):
  537. """
  538. 创建PayPal支付
  539. @param lang: 语言
  540. @param order_id: 订单id
  541. @param price: 价格
  542. @param currency: 货币
  543. @param content: 内容
  544. @return: pay_dict
  545. """
  546. cancel_url = CommonService.get_payment_status_url(lang, 'fail')
  547. call_sub_url = "{}AiService/doPayPalCallBack?orderID={}&lang={}".format(SERVER_DOMAIN_SSL, order_id, lang)
  548. try:
  549. paypalrestsdk.configure(PAYPAL_CRD)
  550. payment = paypalrestsdk.Payment({
  551. "intent": "sale",
  552. "payer": {"payment_method": "paypal"},
  553. "redirect_urls": {"return_url": call_sub_url, "cancel_url": cancel_url},
  554. "transactions": [{
  555. "item_list": {"items": [
  556. {"name": "Cloud video", "sku": "1", "price": price, "currency": "USD", "quantity": 1}]},
  557. "amount": {"total": price, "currency": currency},
  558. "description": content}]})
  559. pay_dict = {}
  560. if not payment.create(): # 创建失败
  561. return pay_dict
  562. payment_id = payment['id'] # 获取payment id
  563. for link in payment.links:
  564. if link.rel == "approval_url":
  565. pay_url = str(link.href)
  566. pay_dict['payment_id'] = payment_id
  567. pay_dict['pay_url'] = pay_url
  568. return pay_dict
  569. return pay_dict
  570. except Exception as e:
  571. print(e)
  572. return {}
  573. @staticmethod
  574. def create_alipay_payment(lang, order_id, price, title, content):
  575. """
  576. 创建支付宝支付
  577. @param lang: 语言
  578. @param order_id: 订单id
  579. @param price: 价格
  580. @param title: 标题
  581. @param content: 内容
  582. @return: pay_dict
  583. """
  584. try:
  585. aliPayObj = AliPayObject()
  586. alipay = aliPayObj.conf()
  587. subject = title + content
  588. order_string = alipay.api_alipay_trade_wap_pay(
  589. out_trade_no=order_id,
  590. total_amount=price,
  591. subject=subject,
  592. return_url="{}web/paid2/success.html".format(SERVER_DOMAIN_SSL),
  593. notify_url="{}AiService/doAlipayCallBack".format(SERVER_DOMAIN_SSL),
  594. quit_url="{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL),
  595. passback_params=quote("lang=" + lang)
  596. )
  597. if not order_string:
  598. return {}
  599. return {'pay_url': aliPayObj.alipay_prefix + order_string}
  600. except Exception as e:
  601. print(e)
  602. return {}
  603. @staticmethod
  604. def create_wechat_payment(lang, order_id, price, ip, content):
  605. """
  606. 创建微信支付
  607. @param lang: 语言
  608. @param order_id: 订单id
  609. @param price: 价格
  610. @param ip: ip
  611. @param content: 内容
  612. @return: pay_dict
  613. """
  614. pay_url = "{}AiService/doWechatCallBack".format(SERVER_DOMAIN_SSL)
  615. try:
  616. pay = WechatPayObject()
  617. content = CommonService.Package_Type(1, content) # AI套餐
  618. pay.get_parameter(order_id, content, float(price) * 100, ip, pay_url, quote("lang=" + lang))
  619. sign_params = pay.re_finall(orderid=order_id)
  620. if not sign_params:
  621. return {}
  622. return {'pay_url': pay_url, 'sign_params': sign_params}
  623. except Exception as e:
  624. print(e)
  625. return {}
  626. @classmethod
  627. def do_paypal_callback(cls, request_dict, response):
  628. """
  629. paypal支付回调
  630. @param request_dict: 请求数据
  631. @request_dict paymentId: 支付id
  632. @request_dict PayerID: 支付账号id
  633. @request_dict orderID: 订单id
  634. @request_dict lang: 语言
  635. @param response: 响应
  636. @return: response
  637. """
  638. logger = logging.getLogger('info')
  639. logger.info('AI订单---paypal支付回调')
  640. payment_id = request_dict.get('paymentId', None)
  641. payer_id = request_dict.get('PayerID', None)
  642. order_id = request_dict.get('orderID', None)
  643. lang = request_dict.get('lang', 'en')
  644. if not order_id:
  645. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  646. return HttpResponseRedirect(pay_failed_url)
  647. # redis加锁,防止订单重复
  648. redis_obj = RedisObject()
  649. isLock = redis_obj.CONN.setnx(order_id + 'creating_ai_order', 1)
  650. redis_obj.CONN.expire(order_id + 'creating_ai_order', 60)
  651. if not isLock:
  652. return response.json(5)
  653. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  654. if not order_qs.exists():
  655. return response.json(173)
  656. try:
  657. paypalrestsdk.configure(PAYPAL_CRD)
  658. payment = paypalrestsdk.Payment.find(payment_id)
  659. payer = payment.execute({'payer_id': payer_id})
  660. if not payer:
  661. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  662. redis_obj.del_data(key=order_id + 'creating_ai_order')
  663. return HttpResponseRedirect(pay_failed_url)
  664. return cls.payment_success(order_id, lang, order_qs, redis_obj)
  665. except Exception as e:
  666. logger.info('AI订单paypal支付回调异常:{}'.format(repr(e)))
  667. order_qs.update(status=10)
  668. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  669. redis_obj.del_data(key=order_id + 'creating_ai_order')
  670. return HttpResponseRedirect(pay_failed_url)
  671. @classmethod
  672. def do_alipay_callback(cls, request_dict, response):
  673. """
  674. 支付宝支付回调
  675. @param request_dict: 请求数据
  676. @param response: 响应
  677. @return: response
  678. """
  679. logger = logging.getLogger('info')
  680. logger.info('AI订单---支付宝支付回调')
  681. data = request_dict.dict()
  682. passback_params = data['passback_params']
  683. params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()])
  684. lang = params['lang']
  685. signature = data['sign']
  686. data.pop('sign')
  687. order_id = data['out_trade_no']
  688. # redis加锁,防止订单重复
  689. redis_obj = RedisObject()
  690. isLock = redis_obj.CONN.setnx(order_id + 'creating_ai_order', 1)
  691. redis_obj.CONN.expire(order_id + 'creating_ai_order', 60)
  692. if not isLock:
  693. return response.json(5)
  694. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  695. if not order_qs.exists():
  696. return response.json(173)
  697. try:
  698. alipay_obj = AliPayObject()
  699. alipay = alipay_obj.conf()
  700. success = alipay.verify(data, signature)
  701. if not success or data['trade_status'] not in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
  702. return response.json(0, signature)
  703. return cls.payment_success(order_id, lang, order_qs, redis_obj)
  704. except Exception as e:
  705. logger.info('AI订单支付宝支付回调异常:{}'.format(repr(e)))
  706. order_qs.update(status=10)
  707. redis_obj.del_data(key=order_id + 'creating_ai_order')
  708. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  709. redis_obj.del_data(key=order_id + 'creating_ai_order')
  710. return HttpResponseRedirect(pay_failed_url)
  711. @classmethod
  712. def do_wechat_callback(cls, request, response):
  713. """
  714. 微信支付回调
  715. @param request: 请求体
  716. @param response: 响应
  717. @return: response
  718. """
  719. logger = logging.getLogger('info')
  720. logger.info('AI订单---微信支付回调')
  721. pay = WechatPayObject()
  722. data = pay.weixinpay_call_back(request.body)
  723. attach = data["attach"]
  724. params = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
  725. lang = params['lang']
  726. trade_status = data['result_code'] # 业务结果 SUCCESS/FAIL
  727. order_id = data['out_trade_no'] # 商户订单号
  728. # redis加锁,防止订单重复
  729. redis_obj = RedisObject()
  730. isLock = redis_obj.CONN.setnx(order_id + 'creating_ai_order', 1)
  731. redis_obj.CONN.expire(order_id + 'creating_ai_order', 60)
  732. if not isLock:
  733. return response.json(5)
  734. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  735. if not order_qs.exists():
  736. return response.json(173)
  737. try:
  738. if trade_status != 'SUCCESS':
  739. order_qs.update(status=10)
  740. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  741. check_sign = pay.get_notifypay(data)
  742. if not check_sign:
  743. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
  744. return cls.payment_success(order_id, lang, order_qs, redis_obj, True)
  745. except Exception as e:
  746. order_qs.update(status=10)
  747. redis_obj.del_data(key=order_id + 'creating_ai_order')
  748. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)}))
  749. @staticmethod
  750. def payment_success(order_id, lang, order_qs, redis_obj, is_wechat_pay=False):
  751. """
  752. 支付成功
  753. @param order_id: 订单id
  754. @param lang: 语言
  755. @param order_qs: 订单QuerySet对象
  756. @param redis_obj: redis对象
  757. @param is_wechat_pay: 是否为微信支付
  758. @return: HttpResponse or HttpResponseRedirect
  759. """
  760. now_time = int(time.time())
  761. order_list = order_qs.values('UID', 'channel', 'commodity_code', 'ai_rank__effective_day', 'isSelectDiscounts',
  762. 'userID__userID', 'userID__username', 'coupon_id')
  763. userid = order_list[0]['userID__userID']
  764. username = order_list[0]['userID__username']
  765. UID = order_list[0]['UID']
  766. channel = order_list[0]['channel']
  767. effective_day = order_list[0]['ai_rank__effective_day']
  768. ai_service_qs = AiService.objects.filter(Q(uid=UID), Q(channel=channel), Q(use_status=1))
  769. ai_service_dict = {'orders_id': order_id,
  770. 'uid': UID,
  771. 'channel': channel,
  772. 'detect_status': 1,
  773. 'addTime': now_time,
  774. 'updTime': now_time,
  775. }
  776. if ai_service_qs.exists(): # 有正在使用的套餐,套餐结束时间保存为套餐有效期
  777. ai_service_dict['endTime'] = effective_day * 24 * 60 * 60
  778. else:
  779. ai_service_dict['use_status'] = 1
  780. ai_service_dict['endTime'] = now_time + effective_day * 24 * 60 * 60
  781. with transaction.atomic():
  782. # 更新设备主用户
  783. Device_Info.objects.filter(UID=UID, vodPrimaryUserID='', vodPrimaryMaster=''). \
  784. update(vodPrimaryUserID=userid, vodPrimaryMaster=username)
  785. # 更新订单数据,返回支付成功url
  786. order_qs.update(status=1, updTime=now_time)
  787. # 创建AiService数据
  788. AiService.objects.create(**ai_service_dict)
  789. pay_success_url = CommonService.get_payment_status_url(lang, 'success')
  790. redis_obj.del_data(key=order_id + 'creating_ai_order')
  791. if is_wechat_pay:
  792. return HttpResponse("<xml>\
  793. <return_code><![CDATA[SUCCESS]]></return_code>\
  794. <return_msg><![CDATA[OK]]></return_msg>\
  795. </xml>")
  796. else:
  797. return HttpResponseRedirect(pay_success_url)