IcloudMeal.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. else:
  53. return response.json(414)
  54. @staticmethod
  55. def get_meal(request_dict, response):
  56. """
  57. 获取套餐
  58. @param request_dict: 请求参数
  59. @request_dict lang: 语言
  60. @param response: 响应对象
  61. @return: response
  62. """
  63. lang = request_dict.get('lang', 'en')
  64. # 隐藏的、删除的套餐不查
  65. cloud_drive_qs = ICloudStoreMeal.objects.filter(Q(lang__lang=lang), Q(is_show=1), Q(is_delete=0)).values(
  66. 'currency', 'symbol', 'price', 'expire',
  67. 'pay_type',
  68. 'size', 'bucket_id', 'lang__title',
  69. 'lang__content', 'sort').order_by(
  70. 'sort')
  71. try:
  72. store_list = list(cloud_drive_qs)
  73. for cloud_drive in store_list:
  74. cloud_drive['title'] = cloud_drive.pop('lang__title')
  75. cloud_drive['content'] = cloud_drive.pop('lang__content')
  76. pay_type_qs = Pay_Type.objects.filter(icloudstoremeal=cloud_drive['pay_type']).values("id", "payment")
  77. cloud_drive['pay_type'] = list(pay_type_qs)
  78. return response.json(0, store_list)
  79. except Exception as e:
  80. print(e)
  81. return response.json(500)
  82. @classmethod
  83. def create_pay_order(cls, request_dict, request, user_id, response):
  84. """
  85. 购买订单
  86. @param request_dict: 请求参数
  87. @param user_id: 用户id
  88. @param request: 请求对象
  89. @request_dict serial_number: 序列号
  90. @param response: 响应对象
  91. @return: response
  92. """
  93. pay_type = request_dict.get('pay_type', None)
  94. rank = request_dict.get('rank', None)
  95. lang = request_dict.get('lang', 'en')
  96. if not all([pay_type, rank]):
  97. return response.json(444, {'error param': 'rank, pay_type'})
  98. user_qs = Device_User.objects.filter(userID=user_id)
  99. if not user_qs.exists():
  100. return response.json(173)
  101. meal_qs = ICloudStoreMeal.objects.filter(id=rank, is_show=1, is_delete=0, lang__lang=lang,
  102. pay_type=pay_type).values('lang__title', 'lang__content', 'currency',
  103. 'price', 'bucket_id')
  104. if not meal_qs.exists():
  105. return response.json(173)
  106. # 查询中文套餐名
  107. icloud_meal_qs = ICloudStoreMeal.objects.filter(id=rank, is_show=1, is_delete=0, lang__lang='cn').values(
  108. 'lang__title',
  109. 'lang__content')
  110. if icloud_meal_qs.exists():
  111. store_meal_name = icloud_meal_qs[0]['lang__title'] + '-' + icloud_meal_qs[0]['lang__content']
  112. else:
  113. store_meal_name = '未知套餐'
  114. pay_type = int(pay_type)
  115. title = meal_qs[0]['lang__title']
  116. content = meal_qs[0]['lang__content']
  117. currency = meal_qs[0]['currency']
  118. price = meal_qs[0]['price']
  119. bucket_id = meal_qs[0]['bucket_id']
  120. now_time = int(time.time())
  121. order_id = CommonService.createOrderID()
  122. price = round(float(price), 2)
  123. order_dict = {
  124. 'orderID': order_id,
  125. 'UID': '',
  126. 'userID_id': user_id,
  127. 'desc': content,
  128. 'payType': pay_type,
  129. 'payTime': now_time,
  130. 'price': price,
  131. 'currency': currency,
  132. 'addTime': now_time,
  133. 'updTime': now_time,
  134. 'ai_rank_id': 1,
  135. 'rank_id': 1,
  136. 'order_type': 4,
  137. 'store_meal_name': store_meal_name,
  138. 'unify_combo_id': rank,
  139. 'uid_bucket_id': bucket_id
  140. }
  141. try:
  142. # 创建订单数据和返回支付回调链接
  143. if pay_type == 1: # PayPal支付
  144. res_dict = cls.create_paypal_payment(lang, order_id, price, currency, content)
  145. if not res_dict:
  146. return response.json(10, 'create ai order failed')
  147. order_dict['paymentID'], order_dict['pay_url'] = res_dict['payment_id'], res_dict['pay_url']
  148. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url']}
  149. elif pay_type == 2: # 支付宝支付
  150. res_dict = cls.create_alipay_payment(lang, order_id, price, title, content)
  151. if not res_dict:
  152. return response.json(10, 'create ai order failed')
  153. order_dict['pay_url'] = res_dict['pay_url']
  154. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url']}
  155. elif pay_type == 3: # 微信支付
  156. ip = CommonService.get_ip_address(request)
  157. res_dict = cls.create_wechat_payment(lang, order_id, price, ip, content)
  158. if not res_dict:
  159. return response.json(10, 'create ai order failed')
  160. order_dict['pay_url'], sign_params = res_dict['pay_url'], res_dict['sign_params']
  161. res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url'], 'result': sign_params}
  162. else:
  163. return response.json(444, {'param': 'pay_type'})
  164. Order_Model.objects.create(**order_dict)
  165. return response.json(0, res_data)
  166. except Exception as e:
  167. logger.info('云盘生成订单异常:{}'.format(repr(e)))
  168. return response.json(500)
  169. @classmethod
  170. def do_paypal_callback(cls, request_dict, response):
  171. """
  172. paypal支付回调
  173. @param request_dict: 请求数据
  174. @request_dict paymentId: 支付id
  175. @request_dict PayerID: 支付账号id
  176. @request_dict orderID: 订单id
  177. @request_dict lang: 语言
  178. @param response: 响应
  179. @return: response
  180. """
  181. logger.info('云盘订单---paypal支付回调')
  182. payment_id = request_dict.get('paymentId', None)
  183. payer_id = request_dict.get('PayerID', None)
  184. order_id = request_dict.get('orderID', None)
  185. lang = request_dict.get('lang', 'en')
  186. if not order_id:
  187. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  188. return HttpResponseRedirect(pay_failed_url)
  189. # redis加锁,防止订单重复
  190. redis_obj = RedisObject()
  191. is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1)
  192. redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60)
  193. if not is_lock:
  194. return response.json(5)
  195. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  196. if not order_qs.exists():
  197. return response.json(173)
  198. try:
  199. paypalrestsdk.configure(PAYPAL_CRD)
  200. payment = paypalrestsdk.Payment.find(payment_id)
  201. payer = payment.execute({'payer_id': payer_id})
  202. if not payer:
  203. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  204. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  205. return HttpResponseRedirect(pay_failed_url)
  206. return cls.payment_success(order_id, lang, order_qs, redis_obj)
  207. except Exception as e:
  208. logger.info('云盘订单paypal支付回调异常:{}'.format(repr(e)))
  209. order_qs.update(status=10)
  210. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  211. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  212. return HttpResponseRedirect(pay_failed_url)
  213. @classmethod
  214. def do_alipay_callback(cls, request_dict, response):
  215. """
  216. 支付宝支付回调
  217. @param request_dict: 请求数据
  218. @param response: 响应
  219. @return: response
  220. """
  221. logger.info('云盘订单---支付宝支付回调')
  222. data = request_dict.dict()
  223. passback_params = data['passback_params']
  224. params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()])
  225. lang = params['lang']
  226. signature = data['sign']
  227. data.pop('sign')
  228. order_id = data['out_trade_no']
  229. # redis加锁,防止订单重复
  230. redis_obj = RedisObject()
  231. is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1)
  232. redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60)
  233. if not is_lock:
  234. return response.json(5)
  235. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  236. if not order_qs.exists():
  237. return response.json(173)
  238. try:
  239. alipay_obj = AliPayObject()
  240. alipay = alipay_obj.conf()
  241. success = alipay.verify(data, signature)
  242. if not success or data['trade_status'] not in ('TRADE_SUCCESS', 'TRADE_FINISHED'):
  243. return response.json(0, signature)
  244. return cls.payment_success(order_id, lang, order_qs, redis_obj)
  245. except Exception as e:
  246. logger.info('AI订单支付宝支付回调异常:{}'.format(repr(e)))
  247. order_qs.update(status=10)
  248. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  249. pay_failed_url = CommonService.get_payment_status_url(lang, 'fail')
  250. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  251. return HttpResponseRedirect(pay_failed_url)
  252. @classmethod
  253. def do_wechat_callback(cls, request, response):
  254. """
  255. 微信支付回调
  256. @param request: 请求体
  257. @param response: 响应
  258. @return: response
  259. """
  260. logger.info('云盘订单---微信支付回调')
  261. pay = WechatPayObject()
  262. data = pay.weixinpay_call_back(request.body)
  263. attach = data["attach"]
  264. params = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
  265. lang = params['lang']
  266. trade_status = data['result_code'] # 业务结果 SUCCESS/FAIL
  267. order_id = data['out_trade_no'] # 商户订单号
  268. # redis加锁,防止订单重复
  269. redis_obj = RedisObject()
  270. is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1)
  271. redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60)
  272. if not is_lock:
  273. return response.json(5)
  274. order_qs = Order_Model.objects.filter(orderID=order_id, status=0)
  275. if not order_qs.exists():
  276. return response.json(173)
  277. try:
  278. if trade_status != 'SUCCESS':
  279. order_qs.update(status=10)
  280. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
  281. check_sign = pay.get_notifypay(data)
  282. if not check_sign:
  283. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
  284. return cls.payment_success(order_id, lang, order_qs, redis_obj, True)
  285. except Exception as e:
  286. order_qs.update(status=10)
  287. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  288. return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)}))
  289. @staticmethod
  290. def payment_success(order_id, lang, order_qs, redis_obj, is_wechat_pay=False):
  291. """
  292. 支付成功
  293. @param order_id: 订单id
  294. @param lang: 语言
  295. @param order_qs: 订单QuerySet对象
  296. @param redis_obj: redis对象
  297. @param is_wechat_pay: 是否为微信支付
  298. @return: HttpResponse or HttpResponseRedirect
  299. """
  300. now_time = int(time.time())
  301. order_list = order_qs.values('unify_combo_id', 'userID__userID', 'userID__username')
  302. user_id = order_list[0]['userID__userID']
  303. rank_id = order_list[0]['unify_combo_id']
  304. icloud_meal_qs = ICloudStoreMeal.objects.filter(rank=rank_id).values('size', 'bucket_id', 'expire')
  305. size = icloud_meal_qs[0]['size']
  306. bucket_id = icloud_meal_qs[0]['bucket_id']
  307. expire = icloud_meal_qs[0]['expire']
  308. end_time = CommonService.calcMonthLater(expire)
  309. icloud_service_dict = {'orders_id': order_id,
  310. 'add_time': now_time,
  311. 'upd_time': now_time,
  312. 'type': 2,
  313. 'size': size,
  314. 'end_time': end_time
  315. }
  316. icloud_use_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id')
  317. if not icloud_use_qs.exists():
  318. icloud_use_qs = IcloudUseDetails.objects.create(add_time=now_time, upd_time=now_time, detect_status=1,
  319. user_id=user_id,
  320. bucket_id=bucket_id)
  321. icloud_service_dict['use_details_id'] = icloud_use_qs.id
  322. else:
  323. icloud_service_dict['use_details_id'] = icloud_use_qs[0]['id']
  324. with transaction.atomic():
  325. # 更新订单数据,返回支付成功url
  326. order_qs.update(status=1, updTime=now_time)
  327. # 创建AiService数据
  328. IcloudService.objects.create(**icloud_service_dict)
  329. pay_success_url = CommonService.get_payment_status_url(lang, 'success')
  330. redis_obj.del_data(key=order_id + 'creating_icloud_order')
  331. if is_wechat_pay:
  332. return HttpResponse("<xml>\
  333. <return_code><![CDATA[SUCCESS]]></return_code>\
  334. <return_msg><![CDATA[OK]]></return_msg>\
  335. </xml>")
  336. else:
  337. return HttpResponseRedirect(pay_success_url)
  338. @staticmethod
  339. def create_paypal_payment(lang, order_id, price, currency, content):
  340. """
  341. 创建PayPal支付
  342. @param lang: 语言
  343. @param order_id: 订单id
  344. @param price: 价格
  345. @param currency: 货币
  346. @param content: 内容
  347. @return: pay_dict
  348. """
  349. cancel_url = CommonService.get_payment_status_url(lang, 'fail')
  350. call_sub_url = "{}icloud/meal/doPayPalCallBack?orderID={}&lang={}".format(SERVER_DOMAIN_SSL, order_id, lang)
  351. try:
  352. paypalrestsdk.configure(PAYPAL_CRD)
  353. payment = paypalrestsdk.Payment({
  354. "intent": "sale",
  355. "payer": {"payment_method": "paypal"},
  356. "redirect_urls": {"return_url": call_sub_url, "cancel_url": cancel_url},
  357. "transactions": [{
  358. "item_list": {"items": [
  359. {"name": "Cloud video", "sku": "1", "price": price, "currency": "USD", "quantity": 1}]},
  360. "amount": {"total": price, "currency": currency},
  361. "description": content}]})
  362. pay_dict = {}
  363. if not payment.create(): # 创建失败
  364. return pay_dict
  365. payment_id = payment['id'] # 获取payment id
  366. for link in payment.links:
  367. if link.rel == "approval_url":
  368. pay_url = str(link.href)
  369. pay_dict['payment_id'] = payment_id
  370. pay_dict['pay_url'] = pay_url
  371. return pay_dict
  372. return pay_dict
  373. except Exception as e:
  374. print(e)
  375. return {}
  376. @staticmethod
  377. def create_alipay_payment(lang, order_id, price, title, content):
  378. """
  379. 创建支付宝支付
  380. @param lang: 语言
  381. @param order_id: 订单id
  382. @param price: 价格
  383. @param title: 标题
  384. @param content: 内容
  385. @return: pay_dict
  386. """
  387. try:
  388. aliPayObj = AliPayObject()
  389. alipay = aliPayObj.conf()
  390. subject = title + content
  391. order_string = alipay.api_alipay_trade_wap_pay(
  392. out_trade_no=order_id,
  393. total_amount=price,
  394. subject=subject,
  395. return_url="{}web/paid2/success.html".format(SERVER_DOMAIN_SSL),
  396. notify_url="{}icloud/meal/doAlipayCallBack".format(SERVER_DOMAIN_SSL),
  397. quit_url="{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL),
  398. passback_params=quote("lang=" + lang)
  399. )
  400. if not order_string:
  401. return {}
  402. return {'pay_url': aliPayObj.alipay_prefix + order_string}
  403. except Exception as e:
  404. print(e)
  405. return {}
  406. @staticmethod
  407. def create_wechat_payment(lang, order_id, price, ip, content):
  408. """
  409. 创建微信支付
  410. @param lang: 语言
  411. @param order_id: 订单id
  412. @param price: 价格
  413. @param ip: ip
  414. @param content: 内容
  415. @return: pay_dict
  416. """
  417. pay_url = "{}icloud/meal/doWechatCallBack".format(SERVER_DOMAIN_SSL)
  418. try:
  419. pay = WechatPayObject()
  420. content = CommonService.Package_Type(4, content) # 云盘套餐
  421. pay.get_parameter(order_id, content, float(price) * 100, ip, pay_url, quote("lang=" + lang))
  422. sign_params = pay.re_finall(orderid=order_id)
  423. if not sign_params:
  424. return {}
  425. return {'pay_url': pay_url, 'sign_params': sign_params}
  426. except Exception as e:
  427. print(e)
  428. return {}