|
@@ -0,0 +1,249 @@
|
|
|
+from Ansjer.config import PAYPAL_CRD,SERVER_DOMAIN,SERVER_DOMAIN_SSL
|
|
|
+from Model.models import PayCycleConfigModel,Order_Model, Store_Meal, UID_Bucket, PromotionRuleModel, Unused_Uid_Meal,Device_Info
|
|
|
+from Service.CommonService import CommonService
|
|
|
+from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
|
|
|
+import requests
|
|
|
+import time
|
|
|
+from Object.ResponseObject import ResponseObject
|
|
|
+import paypalrestsdk
|
|
|
+from paypalrestsdk import BillingAgreement
|
|
|
+from django.views.generic.base import View
|
|
|
+from django.db import transaction
|
|
|
+from Controller import CloudStorage
|
|
|
+from django.db.models import Q, F, Count
|
|
|
+
|
|
|
+#周期扣款相关
|
|
|
+class Paypal:
|
|
|
+ def subscriptions(store_info,lang,orderID):
|
|
|
+ cycle_config = PayCycleConfigModel.objects.filter(id=store_info['cycle_config_id']).values()
|
|
|
+ if not cycle_config:
|
|
|
+ return False
|
|
|
+ cal_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ if lang != 'cn':
|
|
|
+ cal_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ return_url = "{SERVER_DOMAIN_SSL}payCycle/paypalCycleReturn?lang={lang}". \
|
|
|
+ format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, lang=lang)
|
|
|
+ # call_sub_url = "http://binbin.uicp.vip/cloudstorage/dopaypalcallback?orderID={orderID}".format(
|
|
|
+ # SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, orderID=orderID)
|
|
|
+ BillingPlan = {
|
|
|
+ "description": orderID,
|
|
|
+ "merchant_preferences": {
|
|
|
+ "auto_bill_amount": "YES",
|
|
|
+ "cancel_url": cal_url, # 取消协议url
|
|
|
+ "initial_fail_amount_action": "CANCEL",
|
|
|
+ "max_fail_attempts": "1", # 允许的最大失败付款尝试次数
|
|
|
+ "return_url": return_url, # 客户批准协议的url
|
|
|
+ # "notify_url": "http://www.notify.com", #通知客户协议已创建的 URL。只读并保留供将来使用。
|
|
|
+ "setup_fee": {
|
|
|
+ "currency": store_info['currency'],
|
|
|
+ "value": store_info['price'],
|
|
|
+ }
|
|
|
+ },
|
|
|
+ "name": store_info['lang__content'],
|
|
|
+ "payment_definitions": [
|
|
|
+ {
|
|
|
+ "amount": {
|
|
|
+ "currency": store_info['currency'],
|
|
|
+ "value": store_info['price']
|
|
|
+ },
|
|
|
+ # "charge_models": [
|
|
|
+ # {
|
|
|
+ # "amount": {
|
|
|
+ # "currency": "USD",
|
|
|
+ # "value": "20"
|
|
|
+ # },
|
|
|
+ # "type": "TAX" #税金
|
|
|
+ # }
|
|
|
+ # ],
|
|
|
+ "cycles": cycle_config[0]['cycles'],
|
|
|
+ "frequency": cycle_config[0]['frequency'],
|
|
|
+ "frequency_interval": cycle_config[0]['frequencyInterval'],
|
|
|
+ "name": store_info['lang__title'],
|
|
|
+ "type": "REGULAR"
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ "type": "INFINITE",
|
|
|
+ }
|
|
|
+ paypalrestsdk.configure(PAYPAL_CRD)
|
|
|
+ billing_plan = paypalrestsdk.BillingPlan(BillingPlan)
|
|
|
+ if billing_plan.create():
|
|
|
+ billing_plan.activate() # 激活
|
|
|
+ plan_id = billing_plan.id
|
|
|
+ else:
|
|
|
+ print(billing_plan.error)
|
|
|
+ return False
|
|
|
+
|
|
|
+ now_time = int(time.time())
|
|
|
+ start_date_timestamp = CommonService.calcMonthLater(1, now_time) - (5 * 86400) #下次扣款为下个月提前5天扣款
|
|
|
+ start_date_str = CommonService.timestamp_to_str(start_date_timestamp, "%Y-%m-%dT%H:%M:%SZ")
|
|
|
+ #订阅
|
|
|
+ billingAgreement = {
|
|
|
+ "name": store_info['lang__content'],
|
|
|
+ "description": orderID,
|
|
|
+ "start_date": start_date_str,
|
|
|
+ "plan": {
|
|
|
+ "id": plan_id
|
|
|
+ },
|
|
|
+ "payer": {
|
|
|
+ "payment_method": "paypal"
|
|
|
+ },
|
|
|
+ }
|
|
|
+ billing_agreement = paypalrestsdk.BillingAgreement(billingAgreement)
|
|
|
+ # print(billing_agreement.create())
|
|
|
+ if billing_agreement.create():
|
|
|
+ for link in billing_agreement.links:
|
|
|
+ if link.rel == "approval_url":
|
|
|
+ return {"plan_id": plan_id, "url": link.href}
|
|
|
+ else:
|
|
|
+ print(billing_agreement.error)
|
|
|
+ return False
|
|
|
+
|
|
|
+class PaypalCycleNotify(View):
|
|
|
+ def get(self, request, *args, **kwargs):
|
|
|
+ request.encoding = 'utf-8'
|
|
|
+ operation = kwargs.get('operation')
|
|
|
+ return self.validation(request.GET, request, operation)
|
|
|
+
|
|
|
+ def post(self, request, *args, **kwargs):
|
|
|
+ request.encoding = 'utf-8'
|
|
|
+ operation = kwargs.get('operation')
|
|
|
+ return self.validation(request.POST, request, operation)
|
|
|
+
|
|
|
+ def validation(self, request_dict, request, operation):
|
|
|
+ response = ResponseObject()
|
|
|
+ if operation is None:
|
|
|
+ return response.json(444, 'error path')
|
|
|
+ elif operation == 'paypalCycleReturn': # paypal成功订阅回调
|
|
|
+ return self.do_paypal_cycle_return(request_dict, response)
|
|
|
+ elif operation == 'paypalCycleNotify': # paypal 周期付款回调
|
|
|
+ return self.do_paypal_webhook_notify(request_dict, response)
|
|
|
+ def do_paypal_cycle_return(self, request_dict, response):
|
|
|
+ lang = request_dict.get('lang', 'en')
|
|
|
+ token = request_dict.get('token',None)
|
|
|
+ paypalrestsdk.configure(PAYPAL_CRD)
|
|
|
+ billing_agreement = paypalrestsdk.BillingAgreement()
|
|
|
+ billing_agreement_response = billing_agreement.execute(token)
|
|
|
+ if billing_agreement_response.error:
|
|
|
+ print(billing_agreement_response.error)
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ if lang != 'cn':
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ return HttpResponseRedirect(red_url)
|
|
|
+
|
|
|
+ orderID = billing_agreement_response.description
|
|
|
+ agreement_id = billing_agreement_response.id
|
|
|
+ promotion_rule_id = ''
|
|
|
+ try:
|
|
|
+ order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
|
|
|
+
|
|
|
+ if not orderID:
|
|
|
+ print("not orderID")
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ if lang != 'cn':
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ return HttpResponseRedirect(red_url)
|
|
|
+
|
|
|
+ order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
|
|
|
+ "userID__userID",
|
|
|
+ "userID__username")
|
|
|
+ userid = order_list[0]['userID__userID']
|
|
|
+ username = order_list[0]['userID__username']
|
|
|
+ UID = order_list[0]['UID']
|
|
|
+ channel = order_list[0]['channel']
|
|
|
+ rank = order_list[0]['rank']
|
|
|
+ smqs = Store_Meal.objects.filter(id=rank). \
|
|
|
+ values("day", "bucket_id", "bucket__storeDay", "expire")
|
|
|
+ bucketId = smqs[0]['bucket_id']
|
|
|
+ if not smqs.exists():
|
|
|
+ print("not smqs")
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ if lang != 'cn':
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ return HttpResponseRedirect(red_url)
|
|
|
+ # ##
|
|
|
+ ubqs = UID_Bucket.objects.filter(uid=UID).values("id", "bucket_id", "bucket__storeDay", "bucket__region",
|
|
|
+ "endTime", "use_status")
|
|
|
+ expire = smqs[0]['expire']
|
|
|
+
|
|
|
+ if order_list[0]['isSelectDiscounts'] == 1:
|
|
|
+ expire = smqs[0]['expire'] * 2
|
|
|
+ # 是否有促销
|
|
|
+ nowTime = int(time.time())
|
|
|
+ promotion = PromotionRuleModel.objects.filter(status=1, startTime__lte=nowTime,
|
|
|
+ endTime__gte=nowTime).values('id','ruleConfig')
|
|
|
+ if promotion.exists():
|
|
|
+ promotion_rule_id = promotion[0]['id']
|
|
|
+ expire = expire * 2
|
|
|
+ with transaction.atomic():
|
|
|
+ if ubqs.exists():
|
|
|
+ ubq = ubqs[0]
|
|
|
+ if ubq['use_status'] == 1 and ubq['bucket_id'] == bucketId: #套餐使用中并且相同套餐叠加过期时间
|
|
|
+ endTime = CommonService.calcMonthLater(expire, ubq['endTime'])
|
|
|
+ UID_Bucket.objects.filter(id=ubq['id']).update \
|
|
|
+ (uid=UID, channel=channel, bucket_id=bucketId,
|
|
|
+ endTime=endTime, updateTime=nowTime)
|
|
|
+ else: #已过期或者不相同的套餐加入未使用的关联套餐表
|
|
|
+ has_unused = Unused_Uid_Meal.objects.filter(uid=UID, bucket_id=bucketId).values("id")
|
|
|
+ nums = 2 if order_list[0]['isSelectDiscounts'] == 1 else 1
|
|
|
+ if promotion.exists():
|
|
|
+ nums = nums + 1
|
|
|
+ if has_unused.exists():
|
|
|
+ Unused_Uid_Meal.objects.filter(id=has_unused[0]['id']).update(num=F('num') + nums)
|
|
|
+ else:
|
|
|
+ Unused_Uid_Meal.objects.create(uid=UID,channel=channel,addTime=nowTime,num=nums,
|
|
|
+ expire=smqs[0]['expire'],bucket_id=bucketId)
|
|
|
+ UID_Bucket.objects.filter(id=ubq['id']).update(has_unused=1)
|
|
|
+ uid_bucket_id = ubq['id']
|
|
|
+ else:
|
|
|
+ endTime = CommonService.calcMonthLater(expire)
|
|
|
+ ub_cqs = UID_Bucket.objects.create \
|
|
|
+ (uid=UID, channel=channel, bucket_id=bucketId, endTime=endTime, addTime=nowTime,
|
|
|
+ updateTime=nowTime,use_status=1)
|
|
|
+ uid_bucket_id = ub_cqs.id
|
|
|
+
|
|
|
+ dvq = Device_Info.objects.filter(UID=UID, vodPrimaryUserID='', vodPrimaryMaster='')
|
|
|
+ if dvq.exists():
|
|
|
+ dvq_set_update_dict = {
|
|
|
+ 'vodPrimaryUserID': userid,
|
|
|
+ 'vodPrimaryMaster': username
|
|
|
+ }
|
|
|
+ dvq.update(**dvq_set_update_dict)
|
|
|
+
|
|
|
+ # uid_main_exist = UIDMainUser.objects.filter(UID=UID)
|
|
|
+ # if not uid_main_exist.exists():
|
|
|
+ # uid_main_dict = {
|
|
|
+ # 'UID': UID,
|
|
|
+ # 'user_id': userid
|
|
|
+ # }
|
|
|
+ # UIDMainUser.objects.create(**uid_main_dict)
|
|
|
+
|
|
|
+ order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id,
|
|
|
+ promotion_rule_id=promotion_rule_id,agreement_id=agreement_id)
|
|
|
+ datetime = time.strftime("%Y-%m-%d", time.localtime())
|
|
|
+ sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + UID + '设备在' + datetime + '已成功订阅云存套餐',
|
|
|
+ 'Dear customer,you already subscribed the cloud storage package successfully for device ' + UID + ' on ' + time.strftime(
|
|
|
+ "%b %dth,%Y", time.localtime())]
|
|
|
+
|
|
|
+ CloudStorage.CloudStorageView.do_vod_msg_Notice(self, UID, channel, userid, lang, sys_msg_text_list, 'SMS_219738485')
|
|
|
+
|
|
|
+ # return response.json(0)
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ if lang != 'cn':
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ return HttpResponseRedirect(red_url)
|
|
|
+ except Exception as e:
|
|
|
+ print(repr(e))
|
|
|
+ if order_qs:
|
|
|
+ order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ if lang != 'cn':
|
|
|
+ red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
|
|
|
+ return HttpResponseRedirect(red_url)
|
|
|
+
|
|
|
+
|
|
|
+ def do_paypal_webhook_notify(self, request_dict, response):
|
|
|
+ paymentId = request_dict.get('paymentId', None)
|
|
|
+ PayerID = request_dict.get('PayerID', None)
|
|
|
+ lang = request_dict.get('lang', 'en')
|
|
|
+ token = request_dict.get('token',None)
|
|
|
+ paypalrestsdk.configure(PAYPAL_CRD)
|