소스 검색

更新自动续费查询是否有订阅,添加webhook id
更新优惠券状态

lang 3 년 전
부모
커밋
aac20edca3

+ 1 - 0
Ansjer/cn_config/config_formal.py

@@ -29,6 +29,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 
 DETECT_PUSH_DOMAIN = 'http://push.zositechc.cn/'
 DETECT_PUSH_DOMAINS = 'https://push.zositechc.cn/'

+ 1 - 0
Ansjer/cn_config/config_test.py

@@ -36,6 +36,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 # PAYPAL_CRD = {
 #     "mode": "sandbox",  # sandbox or live
 #     "client_id": "ATXTpWs8sajNYeU46jNs1yzpy4H_o3RRrGVIJ8Tscc312BjMx12cpRgCucfWX07a4G6GbK8hzElB04Pd",

+ 1 - 0
Ansjer/eur_config/config_formal.py

@@ -29,6 +29,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 
 DETECT_PUSH_DOMAIN = 'http://push.dvema.com/'
 DETECT_PUSH_DOMAINS = 'https://push.dvema.com/'

+ 1 - 0
Ansjer/eur_config/config_test.py

@@ -35,6 +35,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 # PAYPAL_CRD = {
 #     "mode": "sandbox",  # sandbox or live
 #     "client_id": "ATXTpWs8sajNYeU46jNs1yzpy4H_o3RRrGVIJ8Tscc312BjMx12cpRgCucfWX07a4G6GbK8hzElB04Pd",

+ 1 - 0
Ansjer/us_config/config_formal.py

@@ -24,6 +24,7 @@ PAYPAL_CRD = {
     "client_id": "AdSRd6WBn-qLl9OiQHQuNYTDFSx0ZX0RUttqa58au8bPzoGYQUrt8bc6591RmH8_pEAIPijdvVYSVXyI",
     "client_secret": "ENT-J08N3Fw0B0uAokg4RukljAwO9hFHPf8whE6-Dwd8oBWJO8AWMgpdTKpfB1pOy89t4bsFEzMWDowm"
 }
+PAYPAL_WEB_HOOK_ID = '3YH86681TH784461T'
 # PAYPAL_CRD = {
 #     "mode": "sandbox",  # sandbox or live
 #     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",

+ 1 - 0
Ansjer/us_config/config_test.py

@@ -36,6 +36,7 @@ PAYPAL_CRD = {
     "client_id": "AVLoQVq3xHZ6FrF4mxHwlCPgVBAw4Fw5RtMkuxmYd23SkUTIY643n2g3KdK-Al8wV05I28lza5uoQbAA",
     "client_secret": "EO8kRc8yioDk0i2Qq-QMcVFfwkmyMJorTvBSLDTnxDJJ_wb9VoM_0jkUY9iEng2Flp1ze8wQOGpH5nB2"
 }
+PAYPAL_WEB_HOOK_ID = '6TS30758D98835230'
 # PAYPAL_CRD = {
 #     "mode": "sandbox",  # sandbox or live
 #     "client_id": "ATXTpWs8sajNYeU46jNs1yzpy4H_o3RRrGVIJ8Tscc312BjMx12cpRgCucfWX07a4G6GbK8hzElB04Pd",

+ 11 - 8
Controller/CloudStorage.py

@@ -1008,6 +1008,8 @@ class CloudStorageView(View):
             promotion_rule_id = ''
             if trade_status == "SUCCESS":
                 check_sign = pay.get_notifypay(data)
+                order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
+                                             "userID__userID", "userID__username", "status", "coupon_id")
                 if not check_sign:
                     return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
                 orderID = out_trade_no
@@ -1020,9 +1022,6 @@ class CloudStorageView(View):
                     return response.json(5)
 
                 nowTime = int(time.time())
-                order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
-                                             "userID__userID", "userID__username","status")
-
                 logger.info(order_list[0]['UID'])
                 logger.info(orderID)
 
@@ -1138,7 +1137,6 @@ class CloudStorageView(View):
                 return response.json(10033)
 
         nowTime = int(time.time())
-
         # uq = UID_Bucket.objects.filter(uid=uid,endTime__gt=str(nowTime)).values('endTime')
         # if uq.exists():
         #     return response.json(10033)
@@ -1190,14 +1188,15 @@ class CloudStorageView(View):
             if price < 0:
                 return response.json(10049)
             price = float(price)
-            couponObj.update(use_status=1)
 
         if pay_type == 1:
-            # return HttpResponse(price)
             # 订阅周期扣款
             if(smqs[0]['cycle_config_id']):
+                #查询是否有订阅过,活跃状态
+                checkHasSubscribe = Paypal.checkSubscriptions(userID,uid,rank)
+                if checkHasSubscribe is False:
+                    return response.json(10050)
                 subInfo = Paypal.subscriptions(store_info=smqs[0],lang=lang,orderID=orderID,price=price)
-                #通过plan_id和agrement_id查询,是否活跃状态,活跃状态定制订阅
                 if not subInfo:
                     return response.json(10048)
                 Order_Model.objects.create(orderID=orderID, UID=uid, channel=channel, userID_id=userID,
@@ -1206,8 +1205,12 @@ class CloudStorageView(View):
                                            pay_url=subInfo['url'], isSelectDiscounts=is_select_discount,
                                            commodity_code=commodity_code, commodity_type=commodity_type,
                                            rank_id=rank, plan_id=subInfo['plan_id'],coupon_id=coupon_id)
-                return response.json(0, {"redirectUrl": subInfo['url'], "orderID": orderID})
+                if coupon_id:
+                    #冻结优惠券
+                    CouponModel.objects.filter(id=coupon_id, use_status=0, distributeTime__lte=nowTime,
+                                                           valid_time__gt=nowTime).update(use_status=1)
 
+                return response.json(0, {"redirectUrl": subInfo['url'], "orderID": orderID})
             #正常扣款
             cal_url = "{SERVER_DOMAIN_SSL}web/paid2/fail.html".format(SERVER_DOMAIN_SSL=SERVER_DOMAIN_SSL)
             if lang != 'cn':

+ 35 - 17
Controller/PaymentCycle.py

@@ -1,4 +1,4 @@
-from Ansjer.config import PAYPAL_CRD,SERVER_DOMAIN,SERVER_DOMAIN_SSL
+from Ansjer.config import PAYPAL_CRD,SERVER_DOMAIN,SERVER_DOMAIN_SSL,PAYPAL_WEB_HOOK_ID
 from Model.models import PayCycleConfigModel,Order_Model, Store_Meal, UID_Bucket, PromotionRuleModel, Unused_Uid_Meal,Device_Info, CouponModel
 from Service.CommonService import CommonService
 from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
@@ -19,6 +19,18 @@ from paypalrestsdk import BillingPlan
 
 #周期扣款相关
 class Paypal:
+    #检查是否有重复订阅
+    def checkSubscriptions(userID,uid,rank):
+        hasOrder = Order_Model.objects.filter(userID=userID,UID=uid,rank=rank).values('agreement_id','orderID').order_by('addTime')[0:1]
+        if not hasOrder.exists() or hasOrder[0]['agreement_id'] == '':
+            return True
+        paypalrestsdk.configure(PAYPAL_CRD)
+        billing_agreement = paypalrestsdk.BillingAgreement.find(hasOrder[0]['agreement_id'])
+        if billing_agreement.state == 'Active':
+            return False
+        return True
+
+
     def subscriptions(store_info,lang,orderID,price):
         cycle_config = PayCycleConfigModel.objects.filter(id=store_info['cycle_config_id']).values()
         if not cycle_config:
@@ -144,9 +156,11 @@ class PaypalCycleNotify(View):
         orderID = billing_agreement_response.description
         agreement_id = billing_agreement_response.id
         promotion_rule_id = ''
+        order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
+        order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
+                                     "userID__userID",
+                                     "userID__username", 'coupon_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)
@@ -154,9 +168,6 @@ class PaypalCycleNotify(View):
                     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",'coupon_id')
             userid = order_list[0]['userID__userID']
             username = order_list[0]['userID__username']
             UID = order_list[0]['UID']
@@ -245,6 +256,8 @@ class PaypalCycleNotify(View):
                 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)
+                if order_list[0]['coupon_id'] != '':
+                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)
                 return HttpResponseRedirect(red_url)
         except Exception as e:
             print(repr(e))
@@ -270,7 +283,6 @@ class PaypalCycleNotify(View):
 
         transmission_id = header.get('HTTP_PAYPAL_TRANSMISSION_ID',None)
         transmission_time = header.get('HTTP_PAYPAL_TRANSMISSION_TIME',None)
-        webhook_id = '6TS30758D98835230'
         cert_url = header.get('HTTP_PAYPAL_CERT_URL',None)
         transmission_sig = header.get('HTTP_PAYPAL_TRANSMISSION_SIG',None)
         auth_algo = header.get('HTTP_PAYPAL_AUTH_ALGO',None)
@@ -280,25 +292,25 @@ class PaypalCycleNotify(View):
         if resource_type == 'sale' and paypal_body.get('state') == 'completed':
             paypalrestsdk.configure(PAYPAL_CRD)
             response = paypalrestsdk.WebhookEvent.verify(
-                transmission_id, transmission_time, webhook_id, json_agreement_str, cert_url, transmission_sig, auth_algo)
+                transmission_id, transmission_time, PAYPAL_WEB_HOOK_ID, json_agreement_str, cert_url, transmission_sig, auth_algo)
             logger.info('-----------------------verify')
             logger.info(response)
             if response:
                 try:
                     agreement_id = paypal_body.get('billing_agreement_id')
-                    order_qs = Order_Model.objects.filter(agreement_id=agreement_id, status=1)
+                    billing_agreement = paypalrestsdk.BillingAgreement.find(agreement_id)
+
+                    # 订阅续费订单(如果完成周期数`不是0, 则说明是续费订单,)
+                    if billing_agreement.agreement_details.cycles_completed != '0':
+                        return HttpResponse('fail')
+                    orderID = billing_agreement.description
+                    order_qs = Order_Model.objects.filter(orderID=orderID, status=1)
                     if not order_qs:
-                        return HttpResponse('failss')
+                        return HttpResponse('fail')
                     order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
                                                  "userID__userID","uid_bucket_id",
                                                  "userID__username",'plan_id','addTime','desc','payType','currency','commodity_type')
-                    plan_id = order_list[0]['plan_id']
-                    # plan_cycle = self.get_plan_desc(plan_id)
-                    # 订阅续费订单(如果查到的本地订单已经付过了且包中的完成周期数`不是0, 则说明是续费订单, 本地可以新建一个订单标记是续费的)
                     nowTime = int(time.time())
-                    if(order_list[0]['addTime']+600 > nowTime):
-                        return HttpResponse('success')
-
                     userid = order_list[0]['userID__userID']
                     username = order_list[0]['userID__username']
                     UID = order_list[0]['UID']
@@ -394,6 +406,12 @@ class PaypalCycleNotify(View):
 
 
     def do_test(self, request_dict, request, response):
+        paypalrestsdk.configure(PAYPAL_CRD)
+        billing_agreement = paypalrestsdk.BillingAgreement
+        billing_agreement = billing_agreement.find("I-HT38K76XPMGJ")
+        print("Got Billing Agreement Details for Billing Agreement[%s]" % (
+            billing_agreement.id))
+        exit()
         #normal_pay
         # json_str = '{"id":"WH-8SU832847J141682K-0FF265943E8692615","event_version":"1.0","create_time":"2022-01-10T06:31:49.863Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 0.02 USD","resource":{"amount":{"total":"0.02","currency":"USD","details":{"subtotal":"0.02"}},"payment_mode":"INSTANT_TRANSFER","create_time":"2022-01-10T06:31:45Z","transaction_fee":{"currency":"USD","value":"0.02"},"parent_payment":"PAYID-MHN5E5Y1RH70069CT417990V","update_time":"2022-01-10T06:31:45Z","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","application_context":{"related_qualifiers":[{"id":"0FJ93448LU7282046","type":"CART"}]},"protection_eligibility":"ELIGIBLE","links":[{"method":"GET","rel":"self","href":"https://api.sandbox.paypal.com/v1/payments/sale/6N498138TH641260G"},{"method":"POST","rel":"refund","href":"https://api.sandbox.paypal.com/v1/payments/sale/6N498138TH641260G/refund"},{"method":"GET","rel":"parent_payment","href":"https://api.sandbox.paypal.com/v1/payments/payment/PAYID-MHN5E5Y1RH70069CT417990V"}],"id":"6N498138TH641260G","state":"completed","invoice_number":""},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-8SU832847J141682K-0FF265943E8692615","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-8SU832847J141682K-0FF265943E8692615/resend","rel":"resend","method":"POST"}]}'
         json_agreement_str = '{"id":"WH-9BE23393R5338163R-48P08088YL173821A","event_version":"1.0","create_time":"2022-01-10T10:27:42.925Z","resource_type":"sale","event_type":"PAYMENT.SALE.COMPLETED","summary":"Payment completed for $ 0.02 USD","resource":{"billing_agreement_id":"I-K8PCK2NJC6N6","amount":{"total":"0.02","currency":"USD","details":{"subtotal":"0.02"}},"payment_mode":"INSTANT_TRANSFER","update_time":"2022-01-10T10:27:19Z","create_time":"2022-01-10T10:27:19Z","protection_eligibility_type":"ITEM_NOT_RECEIVED_ELIGIBLE,UNAUTHORIZED_PAYMENT_ELIGIBLE","transaction_fee":{"currency":"USD","value":"0.02"},"protection_eligibility":"ELIGIBLE","links":[{"method":"GET","rel":"self","href":"https://api.sandbox.paypal.com/v1/payments/sale/4H259512Y67055105"},{"method":"POST","rel":"refund","href":"https://api.sandbox.paypal.com/v1/payments/sale/4H259512Y67055105/refund"}],"id":"4H259512Y67055105","state":"completed","invoice_number":""},"links":[{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-9BE23393R5338163R-48P08088YL173821A","rel":"self","method":"GET"},{"href":"https://api.sandbox.paypal.com/v1/notifications/webhooks-events/WH-9BE23393R5338163R-48P08088YL173821A/resend","rel":"resend","method":"POST"}]}'
@@ -425,7 +443,7 @@ class PaypalCycleNotify(View):
         transmission_sig = 'R6sBDhsoq5+FRQHWe+8tSeKJMlRDnt9F2SlWlWVVEfDu9mvQ0zKl74bwcN1zMbvH4o7fWVNbwkcPW70/t4O0YBsj9BcMwL8hDxcuWuHp20RBzaI2dlBpdPEke19wr/fhJKGZCDYuvptV2RJGCSePBn3gKs7hkY5ribELPDqHuajlgVxMmoXm/+CHrMmPo6gSGgTuEMzEn4/ENuj3uJoCkcYqsFx3tUHg6eakUvQ+vYAyflRx9hX7QXEQHp15PWLgGzHkm9zGmnX6YoG5keo5MbJEYh9LfHJjmHmHVErvOtHebJxfTEDZwGoqw+WHr3KqnP4L1gaUj7XIXsQzbiFTBg=='
         auth_algo = 'SHA256withRSA'
         resource_type = 'sale'
-        # self.get_plan_desc('P-4CG284532S612303METMEINY')
+        self.get_plan_desc('P-4CG284532S612303METMEINY')
         if resource_type == 'sale' and paypal_body.get('state') == 'completed':
             # paypalrestsdk.configure(PAYPAL_CRD)
             # response = paypalrestsdk.WebhookEvent.verify(

+ 2 - 0
Object/ResponseObject.py

@@ -106,6 +106,7 @@ class ResponseObject(object):
             10047: 'Please delete all devices under your account first',
             10048: 'Subscribe to the failure',
             10049: 'The coupon is not available',
+            10050: 'You have subscribed to this package, please do not subscribe again',
         }
         data_cn = {
             0: '成功',
@@ -205,6 +206,7 @@ class ResponseObject(object):
             10047: '请先删除您当前帐户下的所有设备',
             10048: '订阅失败',
             10049: '该优惠券不可用',
+            10050: '您已订阅过此套餐,请不要重复订阅',
         }
         if self.lang == 'cn':
             msg = data_cn