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, Order_Model
from Service.CommonService import CommonService
from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
import requests
import time
import sys
from Object.TokenObject import TokenObject
from Object.UidTokenObject import UidTokenObject
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
from paypalrestsdk.notifications import WebhookEvent
import logging
import json
from paypalrestsdk import BillingPlan


#周期扣款相关
class Paypal:
    #检查是否有重复订阅
    def checkSubscriptions(userID,uid,rank):
        hasOrder = Order_Model.objects.filter(UID=uid,rank=rank)
        hasOrder = hasOrder.filter(~Q(agreement_id='')).values('agreement_id','orderID').order_by('-addTime')[0:1]
        if not hasOrder.exists():
            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:
            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)
        # exit(price)
        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": 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())
        if cycle_config[0]['frequency'] == "DAY":
            start_date_timestamp = now_time + 86400 - 3600  # 下次扣款为明天，提前1个小时扣款
            start_date_str = CommonService.timestamp_to_str(start_date_timestamp, "%Y-%m-%dT%H:%M:%SZ")
        elif cycle_config[0]['frequency'] == "MONTH":
            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,request, response)
        elif operation == 'test':  # paypal 周期付款回调
            return self.do_test(request_dict,request, response)
    def do_paypal_cycle_return(self, request_dict, response):
        lang = request_dict.get('lang', 'en')
        token = request_dict.get('token',None)

        logger = logging.getLogger('info')
        logger.info('---------进入paypay自动续费异步回调')
        logger.info(request_dict)


        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

        logger.info('------------billing_agreement_response------')
        logger.info(billing_agreement_response)

        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:
            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)

            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)

                # 核销coupon
                if order_list[0]['coupon_id']:
                    CouponModel.objects.filter(id=order_list[0]['coupon_id']).update(use_status=2)

                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, request, response):
        logger = logging.getLogger('info')
        logger.info('---into---webhook_notify-------')
        logger.info('---request_dict-------')
        logger.info(request_dict)
        json_agreement_str = request.body.decode("utf-8")
        json_obj = json.loads(json_agreement_str)
        header = request.META
        paypal_body = json_obj.get('resource')
        logger.info('-----paypal_body------')
        logger.info(paypal_body)
        logger.info('-----paypal_header------')
        logger.info(header)

        billing_agreement_id = paypal_body.get('billing_agreement_id')
        paypal_transaction_id = paypal_body.get('id')
        amount = paypal_body.get('amount')
        if not billing_agreement_id:
            #普通支付，更新paypal交易id
            paymentID = paypal_body.get('parent_payment')
            if paymentID and paypal_transaction_id:
                Order_Model.objects.filter(paymentID=paymentID).update(
                    updTime=int(time.time()),
                    trade_no=paypal_transaction_id
                )
            return HttpResponse('success')

        transmission_id = header.get('HTTP_PAYPAL_TRANSMISSION_ID',None)
        transmission_time = header.get('HTTP_PAYPAL_TRANSMISSION_TIME',None)
        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)
        resource_type = json_obj.get('resource_type')

        # self.get_plan_desc('P-4CG284532S612303METMEINY')
        if resource_type == 'sale' and paypal_body.get('state') == 'completed':
            paypalrestsdk.configure(PAYPAL_CRD)
            response = paypalrestsdk.WebhookEvent.verify(
                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')
                    billing_agreement = paypalrestsdk.BillingAgreement.find(agreement_id)

                    # 订阅续费订单(如果完成周期数`==0,则是自动续费第一次扣款。否则说明是续费订单)
                    if billing_agreement.agreement_details.cycles_completed == '0':
                        logger.info('----billing_agreement----')
                        logger.info(billing_agreement)
                        logger.info('订阅续费订单完成周期数==0,结束')
                        #更新order表，paypal的商家交易号
                        Order_Model.objects.filter(orderID=billing_agreement.description).update(
                            updTime=int(time.time()),
                            trade_no=paypal_transaction_id
                        )
                        return HttpResponse('success')
                    oldOrderID = billing_agreement.description
                    order_qs = Order_Model.objects.filter(orderID=oldOrderID, status=1)
                    if not order_qs:
                        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','updTime')
                    nowTime = int(time.time())
                    if order_list[0]['addTime'] + 9200 > nowTime:  #避免续费订单重复支付
                        logger.info('-----------------------paypal重复异步回调')
                        return HttpResponse('success')

                    logger.info('-----走入订阅过程-------------')

                    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():
                        return HttpResponse('fail')
                    # ##
                    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 = 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)
                        orderID = CommonService.createOrderID()
                        Order_Model.objects.create(orderID=orderID, UID=UID, channel=channel, userID_id=userid,
                                                   desc=order_list[0]['desc'], payType=order_list[0]['payType'], payTime=nowTime,
                                                   price=amount.get('total'), currency=order_list[0]['currency'], addTime=nowTime, updTime=nowTime,
                                                   pay_url='', isSelectDiscounts=0,commodity_code=order_list[0]['commodity_code'],
                                                   commodity_type=order_list[0]['commodity_type'],rank_id=rank, paymentID='',
                                                   coupon_id='',uid_bucket_id=uid_bucket_id,status=1,agreement_id=agreement_id,
                                                   plan_id=order_list[0]['plan_id'], ai_rank_id=1, trade_no=paypal_transaction_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())]

                        if order_list[0]['payType'] == 1:
                            lang = 'en'
                        else:
                            lang = 'cn'
                        CloudStorage.CloudStorageView.do_vod_msg_Notice(self, UID, channel, userid, lang,
                                                                        sys_msg_text_list, 'SMS_219738485')
                        logger.info('-----------------------result')
                        logger.info('success')

                        #更新agreement
                        billing_agreement_update_attributes = [
                            {
                                "op": "replace",
                                "path": "/",
                                "value": {
                                    "description": orderID,
                                }
                            }
                        ]
                        billing_agreement.replace(billing_agreement_update_attributes)

                        return HttpResponse('success')
                except Exception as e:
                    print(e)
                    logger.info('-----------------------paypal异步回调失败')
                    logger.info(e)
                    return HttpResponse('fail')
        return HttpResponse('fail')


    def do_test(self, request_dict, request, response):
        paypalrestsdk.configure(PAYPAL_CRD)
        billing_agreement = paypalrestsdk.BillingAgreement
        billing_agreement = billing_agreement.find("I-17SRPP7TS71U")
        print("Got Billing Agreement Details for Billing Agreement[%s]" % (
            billing_agreement.id))
        exit(billing_agreement)
        #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"}]}'
        header = {'wsgi.file_wrapper': '<class gunicorn.http.wsgi.FileWrapper>', 'wsgi.version': '(1, 0)', 'HTTP_CONNECTION': 'close', 'wsgi.url_scheme': 'http', 'HTTP_PAYPAL_CERT_URL': 'https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8', 'HTTP_PAYPAL_TRANSMISSION_ID': '022fbbc0-7139-11ec-afa1-0114a54fc1fc', 'SERVER_NAME': '0.0.0.0', 'HTTP_CORRELATION_ID': 'be4c80f0a6c05', 'REMOTE_ADDR': '127.0.0.1', 'HTTP_PAYPAL_TRANSMISSION_SIG': 'IM3Xwyjw5YUgBKPsgyjPdMAh6DSFTtqdwy8zbJBXBhFyB77B6mEqnRfhtEgwwBhag6HsStmKBGIScFhs5Nuraru7DbT4+7Tu5fNx3oQIHeHtR/FYZoQcv86bjZ9cq+Xo04HmhUfgBAsSetS+CuY5TsN60d1m8Hld1MTDjk1UuSbk8HA3dBLiMzWT7wUw3/SUau/C7TtLnWGmdJlkFne+b/5s0+HsuXn3wQQCDIHO0sBMBo72NdlyMlLIunSdoEJ61pKi2U1jQ6qqe/59IrY2q4ufx9D6JZ4bUB6z3NQZ+Gm7zrlKabT6HkVovLJbuBgRgRWWUoY02CuVXZ9w4AzVNQ==', 'REMOTE_PORT': '58060', 'HTTP_ACCEPT': '*/*', 'CONTENT_TYPE': 'application/json', 'HTTP_USER_AGENT': 'PayPal/AUHR-214.0-56015767', 'SCRIPT_NAME': '', 'HTTP_X_FORWARDED_FOR': '173.0.80.117', 'HTTP_HOST': 'test.zositechc.cn:443', 'wsgi.multiprocess': True, 'SERVER_PROTOCOL': 'HTTP/1.0', 'PATH_INFO': '/payCycle/paypalCycleNotify', 'SERVER_SOFTWARE': 'gunicorn/19.7.1', 'wsgi.input': '<gunicorn.http.body.Body object at 0x7fb966cddfd0>', 'REQUEST_METHOD': 'POST', 'wsgi.errors': '<gunicorn.http.wsgi.WSGIErrorsWrapper object at 0x7fb966cdda90>', 'CONTENT_LENGTH': '1226', 'wsgi.run_once': False, 'HTTP_X_B3_SPANID': 'e8ede80526720f95', 'HTTP_PAYPAL_AUTH_ALGO': 'SHA256withRSA', 'QUERY_STRING': '', 'HTTP_PAYPAL_TRANSMISSION_TIME': '2022-01-09T10:43:40Z', 'wsgi.multithread': False, 'HTTP_HTTP_X_FORWARDED_FOR': '173.0.80.117', 'HTTP_X_REAL_IP': '173.0.80.117', 'RAW_URI': '/payCycle/paypalCycleNotify', 'HTTP_PAYPAL_AUTH_VERSION': 'v2', 'gunicorn.socket': '<socket.socket fd=51, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=(127.0.0.1, 8082), raddr=(127.0.0.1, 58060)>', 'SERVER_PORT': '8082'}


        json_obj = json.loads(json_agreement_str)
        paypal_body = json_obj.get('resource')
        billing_agreement_id = paypal_body.get('billing_agreement_id')
        amount = paypal_body.get('amount')
        if not billing_agreement_id:
            return HttpResponse('success')

        nowTime = int(time.time())
        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)
        resource_type = json_obj.get('resource_type')
        # return HttpResponse(resource_type)


        transmission_id = 'f42509f0-71ff-11ec-a473-05e6d85b61e7'
        transmission_time = '2022-01-10T10:27:46Z'
        webhook_id = '3J888119TD851704M'
        cert_url = 'https://api.sandbox.paypal.com/v1/notifications/certs/CERT-360caa42-fca2a594-7a8abba8'
        transmission_sig = 'R6sBDhsoq5+FRQHWe+8tSeKJMlRDnt9F2SlWlWVVEfDu9mvQ0zKl74bwcN1zMbvH4o7fWVNbwkcPW70/t4O0YBsj9BcMwL8hDxcuWuHp20RBzaI2dlBpdPEke19wr/fhJKGZCDYuvptV2RJGCSePBn3gKs7hkY5ribELPDqHuajlgVxMmoXm/+CHrMmPo6gSGgTuEMzEn4/ENuj3uJoCkcYqsFx3tUHg6eakUvQ+vYAyflRx9hX7QXEQHp15PWLgGzHkm9zGmnX6YoG5keo5MbJEYh9LfHJjmHmHVErvOtHebJxfTEDZwGoqw+WHr3KqnP4L1gaUj7XIXsQzbiFTBg=='
        auth_algo = 'SHA256withRSA'
        resource_type = 'sale'
        self.get_plan_desc('P-4CG284532S612303METMEINY')
        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)
            response = True
            if response:
                try:
                    agreement_id = paypal_body.get('billing_agreement_id')
                    order_qs = Order_Model.objects.filter(agreement_id=agreement_id, status=1)
                    if not order_qs:
                        return HttpResponse('failss')
                    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']
                    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():
                        return HttpResponse('fail')
                    # ##
                    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 = 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)
                        orderID = CommonService.createOrderID()
                        Order_Model.objects.create(orderID=orderID, UID=UID, channel=channel, userID_id=userid,
                                                   desc=order_list[0]['desc'], payType=order_list[0]['payType'], payTime=nowTime,
                                                   price=amount.get('total'), currency=order_list[0]['currency'], addTime=nowTime, updTime=nowTime,
                                                   pay_url='', isSelectDiscounts=0,
                                                   commodity_code=order_list[0]['commodity_code'], commodity_type=order_list[0]['commodity_type'],
                                                   rank_id=rank, paymentID='', coupon_id='',uid_bucket_id=uid_bucket_id,status=1,agreement_id=agreement_id,plan_id=order_list[0]['plan_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())]

                        if order_list[0]['payType'] == 1:
                            lang = 'en'
                        else:
                            lang = 'cn'
                        CloudStorage.CloudStorageView.do_vod_msg_Notice(self, UID, channel, userid, lang,
                                                                        sys_msg_text_list, 'SMS_219738485')
                        return HttpResponse('success')
                except Exception as e:
                    print(e)
                    return HttpResponse('fail')
        return HttpResponse('fail')


    def get_plan_desc(self,plan_id):
        paypalrestsdk.configure(PAYPAL_CRD)
        billing_plan = paypalrestsdk.BillingPlan.find(plan_id)
        print("Got Billing Plan Details for Billing Plan[%s]" % (billing_plan.id))
        exit()


class payCycle(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()
        token = request_dict.get('token', None)
        # 设备主键uid
        tko = TokenObject(token)
        response.lang = tko.lang
        if tko.code != 0:
            return response.json(tko.code)
        userID = tko.userID
        if operation is None:
            return response.json(444, 'error path')
        elif operation == 'queryPayCycle':  # paypal成功订阅回调
            return self.do_query_pay_cycle(request_dict,userID, response)
        elif operation == 'cancelPayCycle':  # 取消自动续费
            return self.do_cancel_pay_cycle(request_dict,userID, response)
    def do_query_pay_cycle(self, request_dict, userID, response):
        lang = request_dict.get('lang', 'en')
        uid = request_dict.get('uid',None)
        orderObject = Order_Model.objects.filter(userID=userID,status=1,rank__lang__lang=lang).annotate(rank__title=F('rank__lang__title'), rank__content=F('rank__lang__content'))
        if uid:
            orderObject = orderObject.filter(UID=uid)
        orderObject = orderObject.filter(~Q(agreement_id = ''))
        if not orderObject.exists():
            return response.json(0, {'data':[], 'count': 0})
        orderQuery = orderObject.values("orderID", "UID", "channel", "desc", "price", "currency",
                "addTime",
                "updTime", "paypal", "rank__day", "payType",
                "rank__price", "status",
                "rank__lang__content", "rank__lang__title", "rank__currency",
                "rank_id", "rank__expire","agreement_id").order_by('addTime')
        new_data = []
        values = []
        for d in orderQuery:
            if d['agreement_id'] not in values:
                new_data.append(d)
                values.append(d['agreement_id'])
        count = len(new_data)
        return response.json(0, {'data': new_data, 'count': count})

    def do_cancel_pay_cycle(self, request_dict, userID, response):
        orderID = request_dict.get('orderID', 'None')
        orderObject = Order_Model.objects.filter(orderID=orderID)
        orderObject = orderObject.filter(~Q(agreement_id = '')).values("agreement_id")
        if not orderObject.exists():
            return response.json(800)

        paypalrestsdk.configure(PAYPAL_CRD)
        BILLING_AGREEMENT_ID = orderObject[0]['agreement_id']
        try:
            billing_agreement = paypalrestsdk.BillingAgreement.find(BILLING_AGREEMENT_ID)
            if billing_agreement.state != 'Active':
                Order_Model.objects.filter(agreement_id=BILLING_AGREEMENT_ID).update(agreement_id='')
                return response.json(0)
            cancel_note = {"note": "Canceling the agreement"}
            if billing_agreement.cancel(cancel_note):
                Order_Model.objects.filter(agreement_id=BILLING_AGREEMENT_ID).update(agreement_id='')
                return response.json(0)
            else:
                return response.json(10052)
        except Exception as e:
            return response.json(10052)












