IcloudMeal.py 19 KB

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