# -*- coding: utf-8 -*- """ @Author : peng @Time : 2023-6-7 18:26:35 @File :IcloudMeal.py """ from Ansjer.config import LOGGER import time from urllib.parse import quote, parse_qs, unquote import paypalrestsdk from django.db import transaction, connection from django.db.models import Q, Sum from django.http import HttpResponse, HttpResponseRedirect from django.views import View from Model.models import Device_User, ICloudStoreMeal, Order_Model, IcloudUseDetails, IcloudService, Pay_Type from Object.AliPayObject import AliPayObject from Object.RedisObject import RedisObject from Object.ResponseObject import ResponseObject from Object.TokenObject import TokenObject from Ansjer.config import ACCESS_KEY_ID, SECRET_ACCESS_KEY, REGION_NAME, SERVER_DOMAIN, PAYPAL_CRD, SERVER_DOMAIN_SSL from Object.WechatPayObject import WechatPayObject from Service.CommonService import CommonService from Controller.AiController import AiView class IcloudMeal(View): def get(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.GET, operation, request) def post(self, request, *args, **kwargs): request.encoding = 'utf-8' operation = kwargs.get('operation') return self.validation(request.POST, operation, request) def validation(self, request_dict, operation, request): response = ResponseObject() if operation == 'doPayPalCallBack': # paypal支付回调 return self.do_paypal_callback(request_dict, response) elif operation == 'doAlipayCallBack': # 支付宝支付回调 return self.do_alipay_callback(request_dict, response) elif operation == 'doWechatCallBack': # 微信支付回调 return self.do_wechat_callback(request, response) else: tko = TokenObject(request.META.get('HTTP_AUTHORIZATION')) if tko.code != 0: return response.json(tko.code) response.lang = tko.lang user_id = tko.userID if operation == 'getMeal': # 获取套餐 return self.get_meal(request_dict, response) elif operation == 'createPayOrder': # 购买订单 return self.create_pay_order(request_dict, request, user_id, response) elif operation == 'getCloudDriveInit': # 获取套餐明细 return self.get_cloud_drive_init(request_dict, response, user_id) elif operation == 'getCapacity': # 获取容量 return self.get_capacity(response, user_id) elif operation == 'activateCloudDrive': # 激活云盘 return self.activate_cloud_drive(request_dict, response, user_id) else: return response.json(414) @staticmethod def get_meal(request_dict, response): """ 获取套餐 @param request_dict: 请求参数 @request_dict lang: 语言 @param response: 响应对象 @return: response """ lang = request_dict.get('lang', 'en') # 隐藏的、删除的套餐不查 cloud_drive_qs = ICloudStoreMeal.objects.filter(Q(lang__lang=lang), Q(is_show=1), Q(is_delete=0)).values( 'id', 'currency', 'symbol', 'price', 'expire', 'pay_type', 'size', 'bucket_id', 'lang__title', 'lang__content', 'sort').order_by( 'sort') try: store_list = list(cloud_drive_qs) for cloud_drive in store_list: cloud_drive['title'] = cloud_drive.pop('lang__title') cloud_drive['content'] = cloud_drive.pop('lang__content') pay_type_qs = Pay_Type.objects.filter(id=cloud_drive['pay_type']).values("id", "payment") cloud_drive['pay_type'] = list(pay_type_qs) return response.json(0, store_list) except Exception as e: print(e) return response.json(500) @classmethod def create_pay_order(cls, request_dict, request, user_id, response): """ 购买订单 @param request_dict: 请求参数 @param user_id: 用户id @param request: 请求对象 @request_dict serial_number: 序列号 @param response: 响应对象 @return: response """ pay_type = request_dict.get('pay_type', None) rank = request_dict.get('rank', None) lang = request_dict.get('lang', 'en') if not all([pay_type, rank]): return response.json(444, {'error param': 'rank, pay_type'}) user_qs = Device_User.objects.filter(userID=user_id) if not user_qs.exists(): return response.json(173) icloud_use_qs = IcloudUseDetails.objects.filter(user_id=user_id) if not icloud_use_qs.exists(): return response.json(911) meal_qs = ICloudStoreMeal.objects.filter(id=rank, is_show=1, is_delete=0, lang__lang=lang, pay_type=pay_type).values('lang__title', 'lang__content', 'currency', 'price', 'bucket_id') if not meal_qs.exists(): return response.json(173) # 查询中文套餐名 icloud_meal_qs = ICloudStoreMeal.objects.filter(id=rank, is_show=1, is_delete=0, lang__lang='cn').values( 'lang__title', 'lang__content') if icloud_meal_qs.exists(): store_meal_name = icloud_meal_qs[0]['lang__title'] + '-' + icloud_meal_qs[0]['lang__content'] else: store_meal_name = '未知套餐' pay_type = int(pay_type) title = meal_qs[0]['lang__title'] content = meal_qs[0]['lang__content'] currency = meal_qs[0]['currency'] price = meal_qs[0]['price'] bucket_id = meal_qs[0]['bucket_id'] now_time = int(time.time()) order_id = CommonService.createOrderID() price = round(float(price), 2) order_dict = { 'orderID': order_id, 'UID': '', 'userID_id': user_id, 'desc': content, 'payType': pay_type, 'payTime': now_time, 'price': price, 'currency': currency, 'addTime': now_time, 'updTime': now_time, 'ai_rank_id': 1, 'rank_id': 1, 'order_type': 4, 'store_meal_name': store_meal_name, 'unify_combo_id': rank, 'uid_bucket_id': bucket_id } try: # 创建订单数据和返回支付回调链接 if pay_type == 1: # PayPal支付 res_dict = cls.create_paypal_payment(lang, order_id, price, currency, content) if not res_dict: return response.json(10, 'create icloud order failed') order_dict['paymentID'], order_dict['pay_url'] = res_dict['payment_id'], res_dict['pay_url'] res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url']} elif pay_type == 2: # 支付宝支付 res_dict = cls.create_alipay_payment(lang, order_id, price, title, content) if not res_dict: return response.json(10, 'create icloud order failed') order_dict['pay_url'] = res_dict['pay_url'] res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url']} elif pay_type == 3: # 微信支付 ip = CommonService.get_ip_address(request) res_dict = cls.create_wechat_payment(lang, order_id, price, ip, content) if not res_dict: return response.json(10, 'create icloud order failed') order_dict['pay_url'], sign_params = res_dict['pay_url'], res_dict['sign_params'] res_data = {'orderID': order_id, 'redirectUrl': order_dict['pay_url'], 'result': sign_params} else: return response.json(444, {'param': 'pay_type'}) Order_Model.objects.create(**order_dict) return response.json(0, res_data) except Exception as e: LOGGER.info('云盘生成订单异常:{}'.format(repr(e))) return response.json(500) @classmethod def do_paypal_callback(cls, request_dict, response): """ paypal支付回调 @param request_dict: 请求数据 @request_dict paymentId: 支付id @request_dict PayerID: 支付账号id @request_dict orderID: 订单id @request_dict lang: 语言 @param response: 响应 @return: response """ LOGGER.info('云盘订单---paypal支付回调') payment_id = request_dict.get('paymentId', None) payer_id = request_dict.get('PayerID', None) order_id = request_dict.get('orderID', None) lang = request_dict.get('lang', 'en') if not order_id: pay_failed_url = CommonService.get_payment_status_url(lang, 'fail') return HttpResponseRedirect(pay_failed_url) # redis加锁,防止订单重复 redis_obj = RedisObject() is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1) redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60) if not is_lock: return response.json(5) order_qs = Order_Model.objects.filter(orderID=order_id, status=0) if not order_qs.exists(): return response.json(173) try: paypalrestsdk.configure(PAYPAL_CRD) payment = paypalrestsdk.Payment.find(payment_id) payer = payment.execute({'payer_id': payer_id}) if not payer: pay_failed_url = CommonService.get_payment_status_url(lang, 'fail') redis_obj.del_data(key=order_id + 'creating_icloud_order') return HttpResponseRedirect(pay_failed_url) return cls.payment_success(order_id, lang, order_qs, redis_obj) except Exception as e: LOGGER.info('云盘订单paypal支付回调异常:{}'.format(repr(e))) order_qs.update(status=10) pay_failed_url = CommonService.get_payment_status_url(lang, 'fail') redis_obj.del_data(key=order_id + 'creating_icloud_order') return HttpResponseRedirect(pay_failed_url) @classmethod def do_alipay_callback(cls, request_dict, response): """ 支付宝支付回调 @param request_dict: 请求数据 @param response: 响应 @return: response """ LOGGER.info('云盘订单---支付宝支付回调') data = request_dict.dict() passback_params = data['passback_params'] params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()]) lang = params['lang'] signature = data['sign'] data.pop('sign') order_id = data['out_trade_no'] # redis加锁,防止订单重复 redis_obj = RedisObject() is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1) redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60) if not is_lock: return response.json(5) order_qs = Order_Model.objects.filter(orderID=order_id, status=0) if not order_qs.exists(): return response.json(173) try: alipay_obj = AliPayObject() alipay = alipay_obj.conf() success = alipay.verify(data, signature) if not success or data['trade_status'] not in ('TRADE_SUCCESS', 'TRADE_FINISHED'): return response.json(0, signature) return cls.payment_success(order_id, lang, order_qs, redis_obj) except Exception as e: LOGGER.info('AI订单支付宝支付回调异常:{}'.format(repr(e))) order_qs.update(status=10) redis_obj.del_data(key=order_id + 'creating_icloud_order') pay_failed_url = CommonService.get_payment_status_url(lang, 'fail') redis_obj.del_data(key=order_id + 'creating_icloud_order') return HttpResponseRedirect(pay_failed_url) @classmethod def do_wechat_callback(cls, request, response): """ 微信支付回调 @param request: 请求体 @param response: 响应 @return: response """ LOGGER.info('云盘订单---微信支付回调') pay = WechatPayObject() data = pay.weixinpay_call_back(request.body) attach = data["attach"] params = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()]) lang = params['lang'] trade_status = data['result_code'] # 业务结果 SUCCESS/FAIL order_id = data['out_trade_no'] # 商户订单号 # redis加锁,防止订单重复 redis_obj = RedisObject() is_lock = redis_obj.CONN.setnx(order_id + 'creating_icloud_order', 1) redis_obj.CONN.expire(order_id + 'creating_icloud_order', 60) if not is_lock: return response.json(5) order_qs = Order_Model.objects.filter(orderID=order_id, status=0) if not order_qs.exists(): return response.json(173) try: if trade_status != 'SUCCESS': order_qs.update(status=10) return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'})) check_sign = pay.get_notifypay(data) if not check_sign: return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'})) return cls.payment_success(order_id, lang, order_qs, redis_obj, True) except Exception as e: order_qs.update(status=10) redis_obj.del_data(key=order_id + 'creating_icloud_order') return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)})) @staticmethod def payment_success(order_id, lang, order_qs, redis_obj, is_wechat_pay=False): """ 支付成功 @param order_id: 订单id @param lang: 语言 @param order_qs: 订单QuerySet对象 @param redis_obj: redis对象 @param is_wechat_pay: 是否为微信支付 @return: HttpResponse or HttpResponseRedirect """ now_time = int(time.time()) order_list = order_qs.values('unify_combo_id', 'userID__userID', 'userID__username') user_id = order_list[0]['userID__userID'] rank_id = order_list[0]['unify_combo_id'] icloud_meal_qs = ICloudStoreMeal.objects.filter(id=rank_id).values('size', 'expire') size = icloud_meal_qs[0]['size'] expire = icloud_meal_qs[0]['expire'] end_time = CommonService.calcMonthLater(expire) icloud_service_dict = {'orders_id': order_id, 'add_time': now_time, 'upd_time': now_time, 'type': 2, 'size': size, 'end_time': end_time } icloud_use_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id') icloud_service_dict['use_details_id'] = icloud_use_qs[0]['id'] with transaction.atomic(): # 更新订单数据,返回支付成功url order_qs.update(status=1, updTime=now_time) # 创建AiService数据 IcloudService.objects.create(**icloud_service_dict) pay_success_url = CommonService.get_payment_status_url(lang, 'success') redis_obj.del_data(key=order_id + 'creating_icloud_order') if is_wechat_pay: return HttpResponse("\ \ \ ") else: return HttpResponseRedirect(pay_success_url) @staticmethod def create_paypal_payment(lang, order_id, price, currency, content): """ 创建PayPal支付 @param lang: 语言 @param order_id: 订单id @param price: 价格 @param currency: 货币 @param content: 内容 @return: pay_dict """ cancel_url = CommonService.get_payment_status_url(lang, 'fail') call_sub_url = "{}icloud/meal/doPayPalCallBack?orderID={}&lang={}".format(SERVER_DOMAIN_SSL, order_id, lang) try: paypalrestsdk.configure(PAYPAL_CRD) payment = paypalrestsdk.Payment({ "intent": "sale", "payer": {"payment_method": "paypal"}, "redirect_urls": {"return_url": call_sub_url, "cancel_url": cancel_url}, "transactions": [{ "item_list": {"items": [ {"name": "Cloud video", "sku": "1", "price": price, "currency": "USD", "quantity": 1}]}, "amount": {"total": price, "currency": currency}, "description": content}]}) pay_dict = {} if not payment.create(): # 创建失败 return pay_dict payment_id = payment['id'] # 获取payment id for link in payment.links: if link.rel == "approval_url": pay_url = str(link.href) pay_dict['payment_id'] = payment_id pay_dict['pay_url'] = pay_url return pay_dict return pay_dict except Exception as e: print(e) return {} @staticmethod def create_alipay_payment(lang, order_id, price, title, content): """ 创建支付宝支付 @param lang: 语言 @param order_id: 订单id @param price: 价格 @param title: 标题 @param content: 内容 @return: pay_dict """ try: aliPayObj = AliPayObject() alipay = aliPayObj.conf() subject = title + content order_string = alipay.api_alipay_trade_wap_pay( out_trade_no=order_id, total_amount=price, subject=subject, return_url="{}web/paid2/success.html".format(SERVER_DOMAIN_SSL), notify_url="{}icloud/meal/doAlipayCallBack".format(SERVER_DOMAIN_SSL), quit_url="{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL), passback_params=quote("lang=" + lang) ) if not order_string: return {} return {'pay_url': aliPayObj.alipay_prefix + order_string} except Exception as e: print(e) return {} @staticmethod def create_wechat_payment(lang, order_id, price, ip, content): """ 创建微信支付 @param lang: 语言 @param order_id: 订单id @param price: 价格 @param ip: ip @param content: 内容 @return: pay_dict """ pay_url = "{}icloud/meal/doWechatCallBack".format(SERVER_DOMAIN_SSL) try: pay = WechatPayObject() content = CommonService.Package_Type(4, content) # 云盘套餐 pay.get_parameter(order_id, content, float(price) * 100, ip, pay_url, quote("lang=" + lang)) sign_params = pay.re_finall(orderid=order_id) if not sign_params: return {} return {'pay_url': pay_url, 'sign_params': sign_params} except Exception as e: print(e) return {} @staticmethod def get_cloud_drive_init(request_dict, response, user_id): """ 获取套餐明细 @param request_dict: 请求数据 @request_dict page: 页 @request_dict line: 大小 @request_dict lang: 语言 @param user_id: 用户id @param response: 响应 @return: response """ lang = request_dict.get('lang', 'en') page = request_dict.get('page', None) line = request_dict.get('line', None) if not all([page, line]): return response.json(444) page = int(page) line = int(line) cloud_use_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id') if not cloud_use_qs.exists(): return response.json(0) use_list = [obj['id'] for obj in cloud_use_qs] cloud_service_qs = IcloudService.objects.filter(use_details_id__in=use_list) if not cloud_use_qs.exists(): return response.json(0) try: cloud_service_list = [] count = cloud_service_qs.count() cloud_service_qs = cloud_service_qs.values('use_status', 'type', 'order_id', 'add_time', 'end_time').order_by( '-add_time')[(page - 1) * line:page * line] # 获取套餐明细 for service in cloud_service_qs: data = { 'use_status': service['use_status'], 'type': service['type'], 'order_id': service['order_id'], 'add_time': service['add_time'], 'end_time': service['end_time'], } # 注册永久送 if service['type'] == 0: icloud_meal_qs = ICloudStoreMeal.objects.filter(price=0, expire=0, is_show=0, size=1, pay_type=10, lang__lang=lang).values('lang__title', 'lang__content') data['title'] = icloud_meal_qs[0]['lang__title'] data['note'] = icloud_meal_qs[0]['lang__content'] # 购买云存附送 if service['type'] == 1: orders_qs = Order_Model.objects.filter(orderID=service['order_id'], order_type=0). \ values('desc', 'unify_combo_id') data['note'] = orders_qs[0]['desc'] cloud_store_qs = ICloudStoreMeal.objects.filter(id=orders_qs[0]['unify_combo_id'], lang__lang=lang).values( 'lang__title') data['title'] = cloud_store_qs[0]['lang__title'] # 单独购买套餐 if service['type'] == 2: orders_qs = Order_Model.objects.filter(orderID=service['order_id']).values('desc', 'price', 'currency') data['title'] = orders_qs[0]['desc'] data['note'] = orders_qs[0]['price'] + orders_qs[0]['currency'] cloud_service_list.append(data) return response.json(0, {'data': cloud_service_list, 'count': count}) except Exception as e: LOGGER.info('异常错误,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e))) return response.json(500, e) @staticmethod def get_capacity(response, user_id): """ 获取云盘容量 @param user_id: 用户id @param response: 响应 @return: response """ nowTime = int(time.time()) try: cloud_use_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id').aggregate( total_used_size=Sum('use_size'), id=Sum('id')) cloud_service_qs = IcloudService.objects.filter(Q(use_details_id=cloud_use_qs['id']), Q(use_status=0), Q(end_time__gt=nowTime) | Q(end_time=0)).aggregate( total_size=Sum('size')) data = { 'M_size': round(cloud_use_qs['total_used_size'], 2), 'G_size': round(cloud_service_qs['total_size'], 0) } return response.json(0, data) except Exception as e: LOGGER.info('异常错误,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e))) return response.json(500, e) @staticmethod def activate_cloud_drive(request_dict, response, user_id): """ 激活云盘 @param request_dict: 请求数据 @param user_id: 用户id @param response: 响应 @return: response """ lang = request_dict.get('lang', 'en') now_time = int(time.time()) try: icloud_meal_qs = ICloudStoreMeal.objects.filter(price=0, expire=0, is_show=0, size=1, pay_type=10, lang__lang=lang).values('bucket_id') if not icloud_meal_qs.exists(): return response.json(173) cloud_use_qs = IcloudUseDetails.objects.filter(user_id=user_id).values('id') if not cloud_use_qs.exists(): # 云盘使用 cloud_use_data = { 'use_size': 0, 'add_time': now_time, 'upd_time': now_time, 'detect_status': 1, 'user_id': user_id, 'bucket_id': icloud_meal_qs[0]['bucket_id'] } cloud_use_qs = IcloudUseDetails.objects.create(**cloud_use_data) use_details_id = cloud_use_qs.id else: use_details_id = cloud_use_qs[0]['id'] icloud_service_qs = IcloudService.objects.filter(use_details_id=use_details_id, size=1, end_time=0, type=0) if not icloud_service_qs.exists(): # 云盘服务 cloud_service_data = { 'size': 1, 'end_time': 0, 'add_time': now_time, 'upd_time': now_time, 'use_status': 0, 'use_details_id': use_details_id, 'type': 0, 'order_id': 0 } IcloudService.objects.create(**cloud_service_data) return response.json(0) except Exception as e: LOGGER.info('异常错误,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e))) return response.json(500, e)