IcloudMeal.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. # -*- coding: utf-8 -*-
  2. """
  3. @Author : peng
  4. @Time : 2023-6-7 18:26:35
  5. @File :IcloudMeal.py
  6. """
  7. import logging
  8. import time
  9. from urllib.parse import quote, parse_qs, unquote
  10. import paypalrestsdk
  11. from django.db import transaction
  12. from django.db.models import Q
  13. from django.http import HttpResponse, HttpResponseRedirect
  14. from django.views import View
  15. from Model.models import Device_User, ICloudStoreMeal, Order_Model, IcloudUseDetails, IcloudService, Pay_Type
  16. from Object.AliPayObject import AliPayObject
  17. from Object.RedisObject import RedisObject
  18. from Object.ResponseObject import ResponseObject
  19. from Object.TokenObject import TokenObject
  20. from Ansjer.config import ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME, SERVER_DOMAIN, PAYPAL_CRD, SERVER_DOMAIN_SSL
  21. from Object.WechatPayObject import WechatPayObject
  22. from Service.CommonService import CommonService
  23. from Controller.AiController import AiView
  24. logger = logging.getLogger('info')
  25. class IcloudMeal(View):
  26. def get(self, request, *args, **kwargs):
  27. request.encoding = 'utf-8'
  28. operation = kwargs.get('operation')
  29. return self.validation(request.GET, operation, request)
  30. def post(self, request, *args, **kwargs):
  31. request.encoding = 'utf-8'
  32. operation = kwargs.get('operation')
  33. return self.validation(request.POST, operation, request)
  34. def validation(self, request_dict, operation, request):
  35. response = ResponseObject()
  36. if operation == 'doPayPalCallBack': # paypal支付回调
  37. return self.do_paypal_callback(request_dict, response)
  38. elif operation == 'doAlipayCallBack': # 支付宝支付回调
  39. return self.do_alipay_callback(request_dict, response)
  40. elif operation == 'doWechatCallBack': # 微信支付回调
  41. return self.do_wechat_callback(request, response)
  42. else:
  43. tko = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
  44. if tko.code != 0:
  45. return response.json(tko.code)
  46. response.lang = tko.lang
  47. user_id = tko.userID
  48. if operation == 'getMeal': # 获取套餐
  49. return self.get_meal(request_dict, response)
  50. elif operation == 'createPayOrder': # 购买订单
  51. return self.create_pay_order(request_dict, request, user_id, response)
  52. elif operation == 'getCloudDriveInit': # 获取套餐明细
  53. return self.get_cloud_drive_init(request_dict, response, user_id)
  54. else:
  55. return response.json(414)
  56. @staticmethod
  57. def get_meal(request_dict, response):
  58. """
  59. 获取套餐
  60. @param request_dict: 请求参数
  61. @request_dict lang: 语言
  62. @param response: 响应对象
  63. @return: response
  64. """
  65. lang = request_dict.get('lang', 'en')
  66. # 隐藏的、删除的套餐不查
  67. cloud_drive_qs = ICloudStoreMeal.objects.filter(Q(lang__lang=lang), Q(is_show=1), Q(is_delete=0)).values(
  68. 'id', 'currency', 'symbol', 'price', 'expire',
  69. 'pay_type',
  70. 'size', 'bucket_id', 'lang__title',
  71. 'lang__content', 'sort').order_by(
  72. 'sort')
  73. try:
  74. store_list = list(cloud_drive_qs)
  75. for cloud_drive in store_list:
  76. cloud_drive['title'] = cloud_drive.pop('lang__title')
  77. cloud_drive['content'] = cloud_drive.pop('lang__content')
  78. pay_type_qs = Pay_Type.objects.filter(icloudstoremeal=cloud_drive['pay_type']).values("id", "payment")
  79. cloud_drive['pay_type'] = list(pay_type_qs)
  80. return response.json(0, store_list)
  81. except Exception as e:
  82. print(e)
  83. return response.json(500)
  84. @classmethod
  85. def create_pay_order(cls, request_dict, request, user_id, response):
  86. """
  87. 购买订单
  88. @param request_dict: 请求参数
  89. @param user_id: 用户id
  90. @param request: 请求对象
  91. @request_dict serial_number: 序列号
  92. @param response: 响应对象
  93. @return: response
  94. """
  95. pay_type = request_dict.get('pay_type', None)
  96. rank = request_dict.get('rank', None)
  97. lang = request_dict.get('lang', 'en')
  98. if not all([pay_type, rank]):
  99. return response.json(444, {'error param': 'rank, pay_type'})
  100. user_qs = Device_User.objects.filter(userID=user_id)
  101. if not user_qs.exists():
  102. return response.json(173)
  103. meal_qs = ICloudStoreMeal.objects.filter(id=rank, is_show=1, is_delete=0, lang__lang=lang,
  104. pay_type=pay_type).values('lang__title', 'lang__content', 'currency',
  105. 'price', 'bucket_id')
  106. if not meal_qs.exists():
  107. return response.json(173)
  108. # 查询中文套餐名
  109. icloud_meal_qs = ICloudStoreMeal.objects.filter(id=rank, is_show=1, is_delete=0, lang__lang='cn').values(
  110. 'lang__title',
  111. 'lang__content')
  112. if icloud_meal_qs.exists():
  113. store_meal_name = icloud_meal_qs[0]['lang__title'] + '-' + icloud_meal_qs[0]['lang__content']
  114. else:
  115. store_meal_name = '未知套餐'
  116. pay_type = int(pay_type)
  117. title = meal_qs[0]['lang__title']
  118. content = meal_qs[0]['lang__content']
  119. currency = meal_qs[0]['currency']
  120. price = meal_qs[0]['price']
  121. bucket_id = meal_qs[0]['bucket_id']
  122. now_time = int(time.time())
  123. order_id = CommonService.createOrderID()
  124. price = round(float(price), 2)
  125. order_dict = {
  126. 'orderID': order_id,
  127. 'UID': '',
  128. 'userID_id': user_id,
  129. 'desc': content,
  130. 'payType': pay_type,
  131. 'payTime': now_time,
  132. 'price': price,
  133. 'currency': currency,
  134. 'addTime': now_time,
  135. 'updTime': now_time,
  136. 'ai_rank_id': 1,
  137. 'rank_id': 1,
  138. 'order_type': 4,
  139. 'store_meal_name': store_meal_name,
  140. 'unify_combo_id': rank,
  141. 'uid_bucket_id': bucket_id
  142. }
  143. try:
  144. # 创建订单数据和返回支付回调链接
  145. if pay_type == 1: # PayPal支付
  146. res_dict = cls.create_paypal_payment(lang, order_id, price, currency, content)
  147. if not res_dict:
  148. return response.json(10, 'create ai order failed')
  149. order_dict['paymentID'], order_dict['pay_url'] = res_dict['payment_id'], res_dict['pay_url']
  150. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url']}
  151. elif pay_type == 2: # 支付宝支付
  152. res_dict = cls.create_alipay_payment(lang, order_id, price, title, content)
  153. if not res_dict:
  154. return response.json(10, 'create ai order failed')
  155. order_dict['pay_url'] = res_dict['pay_url']
  156. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url']}
  157. elif pay_type == 3: # 微信支付
  158. ip = CommonService.get_ip_address(request)
  159. res_dict = cls.create_wechat_payment(lang, order_id, price, ip, content)
  160. if not res_dict:
  161. return response.json(10, 'create ai order failed')
  162. order_dict['pay_url'], sign_params = res_dict['pay_url'], res_dict['sign_params']
  163. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url'], 'result': sign_params}
  164. else:
  165. return response.json(444, {'param': 'pay_type'})
  166. Order_Model.objects.create(**order_dict)
  167. return response.json(0, res_data)
  168. except Exception as e:
  169. logger.info('云盘生成订单异常:{}'.format(repr(e)))
  170. return response.json(500)
  171. @classmethod
  172. def do_paypal_callback(cls, request_dict, response):
  173. """
  174. paypal支付回调
  175. @param request_dict: 请求数据
  176. @request_dict paymentId: 支付id
  177. @request_dict PayerID: 支付账号id
  178. @request_dict orderID: 订单id
  179. @request_dict lang: 语言
  180. @param response: 响应
  181. @return: response
  182. """
  183. logger.info('云盘订单---paypal支付回调')
  184. payment_id = request_dict.get('paymentId', None)
  185. payer_id = request_dict.get('PayerID', None)
  186. order_id = request_dict.get('orderID', None)
  187. lang = request_dict.get('lang', 'en')
  188. if not order_id:
  189. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  190. return HttpResponseRedirect(pay_failed_url)
  191. # redis加锁,防止订单重复
  192. redis_obj = RedisObject()
  193. is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1)
  194. redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60)
  195. if not is_lock:
  196. return response.json(5)
  197. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  198. if not order_qs.exists():
  199. return response.json(173)
  200. try:
  201. paypalrestsdk.configure(PAYPAL_CRD)
  202. payment = paypalrestsdk.Payment.find(payment_id)
  203. payer = payment.execute({'payer_id': payer_id})
  204. if not payer:
  205. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  206. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  207. return HttpResponseRedirect(pay_failed_url)
  208. return cls.payment_success(order_id, lang, order_qs, redis_obj)
  209. except Exception as e:
  210. logger.info('云盘订单paypal支付回调异常:{}'.format(repr(e)))
  211. order_qs.update(status=10)
  212. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  213. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  214. return HttpResponseRedirect(pay_failed_url)
  215. @classmethod
  216. def do_alipay_callback(cls, request_dict, response):
  217. """
  218. 支付宝支付回调
  219. @param request_dict: 请求数据
  220. @param response: 响应
  221. @return: response
  222. """
  223. logger.info('云盘订单---支付宝支付回调')
  224. data = request_dict.dict()
  225. passback_params = data['passback_params']
  226. params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()])
  227. lang = params['lang']
  228. signature = data['sign']
  229. data.pop('sign')
  230. order_id = data['out_trade_no']
  231. # redis加锁,防止订单重复
  232. redis_obj = RedisObject()
  233. is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1)
  234. redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60)
  235. if not is_lock:
  236. return response.json(5)
  237. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  238. if not order_qs.exists():
  239. return response.json(173)
  240. try:
  241. alipay_obj = AliPayObject()
  242. alipay = alipay_obj.conf()
  243. success = alipay.verify(data, signature)
  244. if not success or data['trade_status'] not in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
  245. return response.json(0, signature)
  246. return cls.payment_success(order_id, lang, order_qs, redis_obj)
  247. except Exception as e:
  248. logger.info('AI订单支付宝支付回调异常:{}'.format(repr(e)))
  249. order_qs.update(status=10)
  250. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  251. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  252. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  253. return HttpResponseRedirect(pay_failed_url)
  254. @classmethod
  255. def do_wechat_callback(cls, request, response):
  256. """
  257. 微信支付回调
  258. @param request: 请求体
  259. @param response: 响应
  260. @return: response
  261. """
  262. logger.info('云盘订单---微信支付回调')
  263. pay = WechatPayObject()
  264. data = pay.weixinpay_call_back(request.body)
  265. attach = data["attach"]
  266. params = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
  267. lang = params['lang']
  268. trade_status = data['result_code'] # 业务结果 SUCCESS/FAIL
  269. order_id = data['out_trade_no'] # 商户订单号
  270. # redis加锁,防止订单重复
  271. redis_obj = RedisObject()
  272. is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1)
  273. redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60)
  274. if not is_lock:
  275. return response.json(5)
  276. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  277. if not order_qs.exists():
  278. return response.json(173)
  279. try:
  280. if trade_status != 'SUCCESS':
  281. order_qs.update(status=10)
  282. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  283. check_sign = pay.get_notifypay(data)
  284. if not check_sign:
  285. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
  286. return cls.payment_success(order_id, lang, order_qs, redis_obj, True)
  287. except Exception as e:
  288. order_qs.update(status=10)
  289. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  290. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)}))
  291. @staticmethod
  292. def payment_success(order_id, lang, order_qs, redis_obj, is_wechat_pay=False):
  293. """
  294. 支付成功
  295. @param order_id: 订单id
  296. @param lang: 语言
  297. @param order_qs: 订单QuerySet对象
  298. @param redis_obj: redis对象
  299. @param is_wechat_pay: 是否为微信支付
  300. @return: HttpResponse or HttpResponseRedirect
  301. """
  302. now_time = int(time.time())
  303. order_list = order_qs.values('unify_combo_id', 'userID__userID', 'userID__username')
  304. user_id = order_list[0]['userID__userID']
  305. rank_id = order_list[0]['unify_combo_id']
  306. icloud_meal_qs = ICloudStoreMeal.objects.filter(rank=rank_id).values('size', 'bucket_id', 'expire')
  307. size = icloud_meal_qs[0]['size']
  308. bucket_id = icloud_meal_qs[0]['bucket_id']
  309. expire = icloud_meal_qs[0]['expire']
  310. end_time = CommonService.calcMonthLater(expire)
  311. icloud_service_dict = {'orders_id': order_id,
  312. 'add_time': now_time,
  313. 'upd_time': now_time,
  314. 'type': 2,
  315. 'size': size,
  316. 'end_time': end_time
  317. }
  318. icloud_use_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id')
  319. if not icloud_use_qs.exists():
  320. icloud_use_qs = IcloudUseDetails.objects.create(add_time=now_time, upd_time=now_time, detect_status=1,
  321. user_id=user_id,
  322. bucket_id=bucket_id)
  323. icloud_service_dict['use_details_id'] = icloud_use_qs.id
  324. else:
  325. icloud_service_dict['use_details_id'] = icloud_use_qs[0]['id']
  326. with transaction.atomic():
  327. # 更新订单数据,返回支付成功url
  328. order_qs.update(status=1, updTime=now_time)
  329. # 创建AiService数据
  330. IcloudService.objects.create(**icloud_service_dict)
  331. pay_success_url = CommonService.get_payment_status_url(lang, 'success')
  332. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  333. if is_wechat_pay:
  334. return HttpResponse("<xml>\
  335. <return_code><![CDATA[SUCCESS]]></return_code>\
  336. <return_msg><![CDATA[OK]]></return_msg>\
  337. </xml>")
  338. else:
  339. return HttpResponseRedirect(pay_success_url)
  340. @staticmethod
  341. def create_paypal_payment(lang, order_id, price, currency, content):
  342. """
  343. 创建PayPal支付
  344. @param lang: 语言
  345. @param order_id: 订单id
  346. @param price: 价格
  347. @param currency: 货币
  348. @param content: 内容
  349. @return: pay_dict
  350. """
  351. cancel_url = CommonService.get_payment_status_url(lang, 'fail')
  352. call_sub_url = "{}icloud/meal/doPayPalCallBack?orderID={}&lang={}".format(SERVER_DOMAIN_SSL, order_id, lang)
  353. try:
  354. paypalrestsdk.configure(PAYPAL_CRD)
  355. payment = paypalrestsdk.Payment({
  356. "intent": "sale",
  357. "payer": {"payment_method": "paypal"},
  358. "redirect_urls": {"return_url": call_sub_url, "cancel_url": cancel_url},
  359. "transactions": [{
  360. "item_list": {"items": [
  361. {"name": "Cloud video", "sku": "1", "price": price, "currency": "USD", "quantity": 1}]},
  362. "amount": {"total": price, "currency": currency},
  363. "description": content}]})
  364. pay_dict = {}
  365. if not payment.create(): # 创建失败
  366. return pay_dict
  367. payment_id = payment['id'] # 获取payment id
  368. for link in payment.links:
  369. if link.rel == "approval_url":
  370. pay_url = str(link.href)
  371. pay_dict['payment_id'] = payment_id
  372. pay_dict['pay_url'] = pay_url
  373. return pay_dict
  374. return pay_dict
  375. except Exception as e:
  376. print(e)
  377. return {}
  378. @staticmethod
  379. def create_alipay_payment(lang, order_id, price, title, content):
  380. """
  381. 创建支付宝支付
  382. @param lang: 语言
  383. @param order_id: 订单id
  384. @param price: 价格
  385. @param title: 标题
  386. @param content: 内容
  387. @return: pay_dict
  388. """
  389. try:
  390. aliPayObj = AliPayObject()
  391. alipay = aliPayObj.conf()
  392. subject = title + content
  393. order_string = alipay.api_alipay_trade_wap_pay(
  394. out_trade_no=order_id,
  395. total_amount=price,
  396. subject=subject,
  397. return_url="{}web/paid2/success.html".format(SERVER_DOMAIN_SSL),
  398. notify_url="{}icloud/meal/doAlipayCallBack".format(SERVER_DOMAIN_SSL),
  399. quit_url="{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL),
  400. passback_params=quote("lang=" + lang)
  401. )
  402. if not order_string:
  403. return {}
  404. return {'pay_url': aliPayObj.alipay_prefix + order_string}
  405. except Exception as e:
  406. print(e)
  407. return {}
  408. @staticmethod
  409. def create_wechat_payment(lang, order_id, price, ip, content):
  410. """
  411. 创建微信支付
  412. @param lang: 语言
  413. @param order_id: 订单id
  414. @param price: 价格
  415. @param ip: ip
  416. @param content: 内容
  417. @return: pay_dict
  418. """
  419. pay_url = "{}icloud/meal/doWechatCallBack".format(SERVER_DOMAIN_SSL)
  420. try:
  421. pay = WechatPayObject()
  422. content = CommonService.Package_Type(4, content) # 云盘套餐
  423. pay.get_parameter(order_id, content, float(price) * 100, ip, pay_url, quote("lang=" + lang))
  424. sign_params = pay.re_finall(orderid=order_id)
  425. if not sign_params:
  426. return {}
  427. return {'pay_url': pay_url, 'sign_params': sign_params}
  428. except Exception as e:
  429. print(e)
  430. return {}
  431. @staticmethod
  432. def get_cloud_drive_init(request_dict, response, user_id):
  433. """
  434. 获取套餐明细
  435. @param request_dict: 请求数据
  436. @request_dict page: 页
  437. @request_dict line: 大小
  438. @request_dict lang: 语言
  439. @param user_id: 用户id
  440. @param response: 响应
  441. @return: response
  442. """
  443. lang = request_dict.get('lang', 'en')
  444. page = request_dict.get('page', None)
  445. line = request_dict.get('line', None)
  446. if not all([page, line]):
  447. return response.json(444)
  448. page = int(page)
  449. line = int(line)
  450. cloud_use_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id')
  451. if not cloud_use_qs.exists():
  452. return response.json(0)
  453. use_list = [obj['id'] for obj in cloud_use_qs]
  454. cloud_service_qs = IcloudService.objects.filter(use_details_id__in=use_list)
  455. if not cloud_use_qs.exists():
  456. return response.json(0)
  457. try:
  458. data = {}
  459. cloud_service_list = []
  460. count = cloud_service_qs.count()
  461. cloud_service_qs = cloud_service_qs[(page - 1) * line:page * line].values('use_status', 'type',
  462. 'order_id',
  463. 'add_time', 'end_time').order_by(
  464. '-add_time')
  465. # 获取套餐明细
  466. for service in cloud_service_qs:
  467. data['use_status'] = service['use_status']
  468. data['type'] = service['type']
  469. data['order_id'] = service['order_id']
  470. data['add_time'] = service['add_time']
  471. data['end_time'] = service['end_time']
  472. if service['type'] == 0:
  473. if lang == 'cn':
  474. data['title'] = '1G永久套餐'
  475. data['note'] = '赠送'
  476. if lang == 'en':
  477. data['title'] = '1G Permanent Package'
  478. data['note'] = 'Gift'
  479. if service['type'] == 1:
  480. orders_qs = Order_Model.objects.filter(orderID=service['order_id'], order_type=4). \
  481. values('desc', 'unify_combo_id')
  482. data['note'] = orders_qs[0]['desc']
  483. cloud_store_qs = ICloudStoreMeal.objects.filter(id=orders_qs[0]['unify_combo_id'],
  484. lang__lang=lang).values(
  485. 'lang__title')
  486. data['title'] = cloud_store_qs[0]['lang__title']
  487. if service['type'] == 2:
  488. orders_qs = Order_Model.objects.filter(orderID=service['order_id']).values('desc', 'price',
  489. 'currency')
  490. data['title'] = orders_qs[0]['desc']
  491. data['note'] = orders_qs[0]['price'] + orders_qs[0]['currency']
  492. cloud_service_list.append(data)
  493. return response.json(0, {'data': cloud_service_list, 'count': count})
  494. except Exception as e:
  495. logging.info('异常错误,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
  496. return response.json(500, e)