PaymentCycle.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. from Object import PaypalObject
  2. from Ansjer.config import PAYPAL_CRD,SERVER_DOMAIN,SERVER_DOMAIN_SSL
  3. from Model.models import PayCycleConfigModel,Order_Model, Store_Meal, UID_Bucket, PromotionRuleModel, Unused_Uid_Meal,Device_Info
  4. from Service.CommonService import CommonService
  5. from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
  6. import requests
  7. import time
  8. from Object.ResponseObject import ResponseObject
  9. import paypalrestsdk
  10. from paypalrestsdk import BillingAgreement
  11. from django.views.generic.base import View
  12. from django.db import transaction
  13. from Controller import CloudStorage
  14. from django.db.models import Q, F, Count
  15. #周期扣款相关
  16. class Paypal:
  17. def subscriptions(store_info,lang,orderID):
  18. cycle_config = PayCycleConfigModel.objects.filter(id=store_info['cycle_config_id']).values()
  19. if not cycle_config:
  20. return False
  21. cal_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
  22. if lang != 'cn':
  23. cal_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
  24. return_url = "{SERVER_DOMAIN_SSL}payCycle/paypalCycleReturn?lang={lang}". \
  25. format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, lang=lang)
  26. # call_sub_url = "http://binbin.uicp.vip/cloudstorage/dopaypalcallback?orderID={orderID}".format(
  27. # SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL, orderID=orderID)
  28. BillingPlan = {
  29. "description": orderID,
  30. "merchant_preferences": {
  31. "auto_bill_amount": "YES",
  32. "cancel_url": cal_url, # 取消协议url
  33. "initial_fail_amount_action": "CANCEL",
  34. "max_fail_attempts": "1", # 允许的最大失败付款尝试次数
  35. "return_url": return_url, # 客户批准协议的url
  36. # "notify_url": "http://www.notify.com", #通知客户协议已创建的 URL。只读并保留供将来使用。
  37. "setup_fee": {
  38. "currency": store_info['currency'],
  39. "value": store_info['price'],
  40. }
  41. },
  42. "name": store_info['lang__content'],
  43. "payment_definitions": [
  44. {
  45. "amount": {
  46. "currency": store_info['currency'],
  47. "value": store_info['price']
  48. },
  49. # "charge_models": [
  50. # {
  51. # "amount": {
  52. # "currency": "USD",
  53. # "value": "20"
  54. # },
  55. # "type": "TAX" #税金
  56. # }
  57. # ],
  58. "cycles": cycle_config[0]['cycles'],
  59. "frequency": cycle_config[0]['frequency'],
  60. "frequency_interval": cycle_config[0]['frequencyInterval'],
  61. "name": store_info['lang__title'],
  62. "type": "REGULAR"
  63. },
  64. ],
  65. "type": "INFINITE",
  66. }
  67. paypalrestsdk.configure(PAYPAL_CRD)
  68. billing_plan = paypalrestsdk.BillingPlan(BillingPlan)
  69. if billing_plan.create():
  70. billing_plan.activate() # 激活
  71. plan_id = billing_plan.id
  72. else:
  73. return False
  74. now_time = int(time.time())
  75. start_date_timestamp = CommonService.calcMonthLater(1, now_time) - (5 * 86400) #下次扣款为下个月提前5天扣款
  76. start_date_str = CommonService.timestamp_to_str(start_date_timestamp, "%Y-%m-%dT%H:%M:%SZ")
  77. #订阅
  78. billingAgreement = {
  79. "name": store_info['lang__content'],
  80. "description": orderID,
  81. "start_date": start_date_str,
  82. "plan": {
  83. "id": plan_id
  84. },
  85. "payer": {
  86. "payment_method": "paypal"
  87. },
  88. }
  89. billing_agreement = paypalrestsdk.BillingAgreement(billingAgreement)
  90. # print(billing_agreement.create())
  91. if billing_agreement.create():
  92. for link in billing_agreement.links:
  93. if link.rel == "approval_url":
  94. print("-------------------")
  95. return {"plan_id": plan_id, "url": link.href}
  96. else:
  97. print(billing_agreement.error)
  98. return False
  99. class PaypalCycleNotify(View):
  100. def get(self, request, *args, **kwargs):
  101. request.encoding = 'utf-8'
  102. operation = kwargs.get('operation')
  103. return self.validation(request.GET, request, operation)
  104. def post(self, request, *args, **kwargs):
  105. request.encoding = 'utf-8'
  106. operation = kwargs.get('operation')
  107. return self.validation(request.POST, request, operation)
  108. def validation(self, request_dict, request, operation):
  109. response = ResponseObject()
  110. if operation is None:
  111. return response.json(444, 'error path')
  112. elif operation == 'paypalCycleReturn': # paypal成功订阅回调
  113. return self.do_paypal_cycle_return(request_dict, response)
  114. elif operation == 'paypalCycleNotify': # paypal 周期付款回调
  115. return self.do_paypal_webhook_notify(request_dict, response)
  116. def do_paypal_cycle_return(self, request_dict, response):
  117. paymentId = request_dict.get('paymentId', None)
  118. PayerID = request_dict.get('PayerID', None)
  119. lang = request_dict.get('lang', 'en')
  120. token = request_dict.get('token',None)
  121. paypalrestsdk.configure(PAYPAL_CRD)
  122. billing_agreement = paypalrestsdk.BillingAgreement()
  123. billing_agreement_response = billing_agreement.execute("EC-93848356GS252673L")
  124. if billing_agreement_response.error:
  125. return False
  126. orderID = billing_agreement_response.description
  127. agreement_id = billing_agreement_response.id
  128. try:
  129. order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
  130. if not orderID:
  131. red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
  132. if lang != 'cn':
  133. red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
  134. return HttpResponseRedirect(red_url)
  135. order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
  136. "userID__userID",
  137. "userID__username")
  138. userid = order_list[0]['userID__userID']
  139. username = order_list[0]['userID__username']
  140. UID = order_list[0]['UID']
  141. channel = order_list[0]['channel']
  142. rank = order_list[0]['rank']
  143. smqs = Store_Meal.objects.filter(id=rank). \
  144. values("day", "bucket_id", "bucket__storeDay", "expire")
  145. bucketId = smqs[0]['bucket_id']
  146. if not smqs.exists():
  147. return response.json(173)
  148. # ##
  149. ubqs = UID_Bucket.objects.filter(uid=UID).values("id", "bucket_id", "bucket__storeDay", "bucket__region",
  150. "endTime", "use_status")
  151. expire = smqs[0]['expire']
  152. if order_list[0]['isSelectDiscounts'] == 1:
  153. expire = smqs[0]['expire'] * 2
  154. # 是否有促销
  155. nowTime = int(time.time())
  156. promotion = PromotionRuleModel.objects.filter(status=1, startTime__lte=nowTime,
  157. endTime__gte=nowTime).values('id','ruleConfig')
  158. promotion_rule_id = ''
  159. if promotion.exists():
  160. promotion_rule_id = promotion[0]['id']
  161. expire = expire * 2
  162. with transaction.atomic():
  163. if ubqs.exists():
  164. ubq = ubqs[0]
  165. if ubq['use_status'] == 1 and ubq['bucket_id'] == bucketId: #套餐使用中并且相同套餐叠加过期时间
  166. endTime = CommonService.calcMonthLater(expire, ubq['endTime'])
  167. UID_Bucket.objects.filter(id=ubq['id']).update \
  168. (uid=UID, channel=channel, bucket_id=bucketId,
  169. endTime=endTime, updateTime=nowTime)
  170. else: #已过期或者不相同的套餐加入未使用的关联套餐表
  171. has_unused = Unused_Uid_Meal.objects.filter(uid=UID, bucket_id=bucketId).values("id")
  172. nums = 2 if order_list[0]['isSelectDiscounts'] == 1 else 1
  173. if promotion.exists():
  174. nums = nums + 1
  175. if has_unused.exists():
  176. Unused_Uid_Meal.objects.filter(id=has_unused[0]['id']).update(num=F('num') + nums)
  177. else:
  178. Unused_Uid_Meal.objects.create(uid=UID,channel=channel,addTime=nowTime,num=nums,
  179. expire=smqs[0]['expire'],bucket_id=bucketId)
  180. UID_Bucket.objects.filter(id=ubq['id']).update(has_unused=1)
  181. uid_bucket_id = ubq['id']
  182. else:
  183. endTime = CommonService.calcMonthLater(expire)
  184. ub_cqs = UID_Bucket.objects.create \
  185. (uid=UID, channel=channel, bucket_id=bucketId, endTime=endTime, addTime=nowTime,
  186. updateTime=nowTime,use_status=1)
  187. uid_bucket_id = ub_cqs.id
  188. dvq = Device_Info.objects.filter(UID=UID, vodPrimaryUserID='', vodPrimaryMaster='')
  189. if dvq.exists():
  190. dvq_set_update_dict = {
  191. 'vodPrimaryUserID': userid,
  192. 'vodPrimaryMaster': username
  193. }
  194. dvq.update(**dvq_set_update_dict)
  195. # uid_main_exist = UIDMainUser.objects.filter(UID=UID)
  196. # if not uid_main_exist.exists():
  197. # uid_main_dict = {
  198. # 'UID': UID,
  199. # 'user_id': userid
  200. # }
  201. # UIDMainUser.objects.create(**uid_main_dict)
  202. order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id,
  203. promotion_rule_id=promotion_rule_id,agreement_id=agreement_id)
  204. datetime = time.strftime("%Y-%m-%d", time.localtime())
  205. sys_msg_text_list = ['温馨提示:尊敬的客户,您的' + UID + '设备在' + datetime + '已成功订阅云存套餐',
  206. 'Dear customer,you already subscribed the cloud storage package successfully for device ' + UID + ' on ' + time.strftime(
  207. "%b %dth,%Y", time.localtime())]
  208. CloudStorage.CloudStorageView.do_vod_msg_Notice(UID, channel, userid, lang, sys_msg_text_list, 'SMS_219738485')
  209. # return response.json(0)
  210. red_url = "{SERVER_DOMAIN_SSL}web/paid2/success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
  211. if lang != 'cn':
  212. red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_success.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
  213. return HttpResponseRedirect(red_url)
  214. except Exception as e:
  215. print(repr(e))
  216. if order_qs:
  217. order_qs.update(status=10, promotion_rule_id=promotion_rule_id)
  218. red_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
  219. if lang != 'cn':
  220. red_url = "{SERVER_DOMAIN_SSL}web/paid2/en_fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
  221. return HttpResponseRedirect(red_url)
  222. def do_paypal_webhook_notify(self, request_dict, response):
  223. paymentId = request_dict.get('paymentId', None)
  224. PayerID = request_dict.get('PayerID', None)
  225. lang = request_dict.get('lang', 'en')
  226. token = request_dict.get('token',None)
  227. paypalrestsdk.configure(PAYPAL_CRD)