import datetime as date_time
import json
import logging
import time
import traceback

import paypalrestsdk
from django.db import transaction
from django.db.models import Q, F
from django.http import HttpResponseRedirect, HttpResponse
from django.views.generic.base import View

from Ansjer.config import PAYPAL_CRD, SERVER_DOMAIN_SSL, PAYPAL_WEB_HOOK_ID, PAYPAL_WEB_HOOK_ID_TWO, CONFIG_INFO, \
    CONFIG_US, CONFIG_EUR
from Controller import CloudStorage
from Model.models import PayCycleConfigModel, Store_Meal, UID_Bucket, PromotionRuleModel, \
    Unused_Uid_Meal, Device_Info, CouponModel, Order_Model, PaypalWebHookEvent, CountryModel, AiService
from Object.ResponseObject import ResponseObject
from Object.TokenObject import TokenObject
from Service.CommonService import CommonService

PAY_LOGGER = logging.getLogger('pay')


# 周期扣款相关
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):
        logger = logging.getLogger('pay')
        cycle_config = PayCycleConfigModel.objects.filter(id=store_info['cycle_config_id']).values()
        if not cycle_config:
            logger.info('----创建订阅失败----')
            logger.info('订阅配置失败')
            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:
            logger.info('----创建计划失败----')
            logger.info(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:
            logger.info('----创建订阅失败----')
            logger.info(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 == 'subscriptionBreakNotify':  # paypal 订阅相关回调
            return self.do_subscription_break_notify(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('pay')
        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:
            logger.info('----付款失败----')
            logger.info(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
        state = billing_agreement_response.state
        nowTime = int(time.time())
        promotion_rule_id = ''
        logger.info('----订阅详情----')
        logger.info(billing_agreement_response)
        agreement_id = billing_agreement_response.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')
        if not orderID:
            logger.info('----订阅订单号失效----')
            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)
        UID = order_list[0]['UID']
        if state != 'Active':
            order_qs.update(status=2, promotion_rule_id=promotion_rule_id)
            logger.info('----UID:{UID},用户名:{last_time} {first_time}首次订阅付款失败----'.format
                        (UID=UID,
                         last_time=billing_agreement_response.payer.payer_info.last_name,
                         first_time=billing_agreement_response.payer.payer_info.first_time,
                         ))
            logger.info('billing_agreement_state')
            logger.info(state)
            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)
        try:
            userid = order_list[0]['userID__userID']
            username = order_list[0]['userID__username']
            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():
                logger.info('----订阅套餐失效----')
                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
            # 是否有促销
            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, update_time=nowTime)

                order_qs.update(status=1, updTime=nowTime, uid_bucket_id=uid_bucket_id,
                                promotion_rule_id=promotion_rule_id, agreement_id=agreement_id)
                # 如果存在序列号,消息提示用序列号
                device_name = CommonService.query_serial_with_uid(uid=UID)
                datetime = time.strftime("%Y-%m-%d", time.localtime())
                sys_msg_text_list = [
                    '温馨提示：尊敬的客户，您的' + device_name + '设备在' + datetime + '已成功订阅云存套餐',
                    'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
                        "%b %dth,%Y", time.localtime())]
                CloudStorage.CloudStorageView().do_vod_msg_notice(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)
                logger.info('{UID}成功开通paypal自动续费：----'.format(UID=UID))
                return HttpResponseRedirect(red_url)
        except Exception as e:
            print(repr(e))
            logger.info('do_paypal_cycle_return支付失败：----')
            logger.info('{UID}开通paypal自动续费失败'.format(UID=UID))
            logger.info("错误行数：{errLine}".format(errLine=e.__traceback__.tb_lineno))
            logger.info(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)

    @staticmethod
    def paypal_webhook_log(**params):
        """
        webhook日志存库
        @param params:
        @return:
        """
        logger = logging.getLogger('pay')
        try:
            params['agreement_desc'] = 'webhook'
            PaypalWebHookEvent.objects.create(**params)
            logger.info('《Webhook日志存库Success......》')
            return True
        except Exception as e:
            logger.info(e.args)
            ex = traceback.format_exc()
            logger.info(ex)
            return True

    def do_paypal_webhook_notify(self, request_dict, request, response):
        PAY_LOGGER.info('--------进入周期扣款钩子--------')
        if not request.body:
            PAY_LOGGER.info('PayPal周期扣款失败---缺失请求体')
            return HttpResponse('fail', status=500)
        json_agreement_str = request.body.decode("utf-8")
        json_obj = json.loads(json_agreement_str)
        header = request.META
        paypal_body = json_obj.get('resource')
        PAY_LOGGER.info('----请求体数据:{}----'.format(json_agreement_str))
        PAY_LOGGER.info('----请求头数据:{}----'.format(header))
        try:
            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)
            event_type = json_obj.get('event_type')
            summary = json_obj.get('summary')
            resource_type = json_obj.get('resource_type')
            billing_agreement_id = paypal_body.get('billing_agreement_id')
            paypal_transaction_id = paypal_body.get('id')
            amount = paypal_body.get('amount')
            PaypalWebHookEventInsert = {
                'webhook_event_id': json_obj.get('id'),
                'resource_type': json_obj.get('resource_type'),
                'event_type': 1,
                'summary': summary,
                'trade_no': paypal_transaction_id,
                'resource': json_agreement_str,
                'created_time': int(time.time()),
            }
            self.paypal_webhook_log(**PaypalWebHookEventInsert)
            if event_type != 'PAYMENT.SALE.COMPLETED':
                PAY_LOGGER.info('----event_type异常:{}----'.format(event_type))

            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)
                if not response:
                    PAY_LOGGER.info('PayPal周期扣款失败---签名验证失败')
                    return HttpResponse('Fail', status=500)
            else:
                PAY_LOGGER.info('PayPal周期扣款失败,付款状态有误,resource_type:{},state:{}----'.
                                format(resource_type, paypal_body.get('state')))
                return HttpResponse('Fail', status=500)

            nowTime = int(time.time())
            if not billing_agreement_id:
                # 记录钩子日志
                PaypalWebHookEvent.objects.create(**PaypalWebHookEventInsert)

                # 普通支付，更新paypal交易id
                paymentID = paypal_body.get('parent_payment')
                if paymentID and paypal_transaction_id:
                    # 查询客户地区信息,地区跟服务器配置不匹配,返回500
                    order_qs = Order_Model.objects.filter(paymentID=paymentID).values('UID', 'userID__region_country')
                    if not order_qs.exists():
                        PAY_LOGGER.info('PayPal周期扣款失败---根据paymentID查询订单数据不存在')
                        return HttpResponse('Fail', status=500)

                    # 判断用户地区是否跟服务器地区匹配
                    uid = order_qs[0]['UID']
                    country_id = order_qs[0]['userID__region_country']
                    if not self.config_match_region(uid, country_id):
                        return HttpResponse('Fail', status=500)

                    order_qs.update(status=1, updTime=nowTime, trade_no=paypal_transaction_id)
                    PAY_LOGGER.info('PayPal周期扣款成功---更新交易id:{}'.format(paypal_transaction_id))
                    return HttpResponse('success')
                else:
                    PAY_LOGGER.info('PayPal周期扣款失败---paymentID:{}或paypal_transaction_id:{}为空'.
                                    format(paymentID, paypal_transaction_id))
                    return HttpResponse('fail', status=500)

            agreement_id = paypal_body.get('billing_agreement_id')
            billing_agreement = paypalrestsdk.BillingAgreement.find(agreement_id)
            PAY_LOGGER.info('billing_agreement:{}'.format(billing_agreement))

            # 记录钩子日志
            PaypalWebHookEventInsert['agreement_desc'] = repr(billing_agreement)
            PaypalWebHookEventInsert['agreement_id'] = agreement_id
            PaypalWebHookEventInsert['orderID'] = billing_agreement.description
            PaypalWebHookEvent.objects.create(**PaypalWebHookEventInsert)

            # 查询订单数据
            order_id = billing_agreement.description
            order_qs = Order_Model.objects.filter(orderID=order_id).values('UID', 'channel', 'commodity_code', 'rank',
                                                                           'isSelectDiscounts', 'plan_id', 'desc',
                                                                           'payType', 'currency', 'addTime',
                                                                           'commodity_type', 'updTime',
                                                                           'userID__userID', 'uid_bucket_id',
                                                                           'userID__username', 'userID__region_country'
                                                                           )
            if not order_qs.exists():
                PAY_LOGGER.info('PayPal周期扣款失败---根据order_id查询订单数据不存在')
                return HttpResponse('fail', status=500)

            # 判断用户地区是否跟服务器地区匹配
            uid = order_qs[0]['UID']
            country_id = order_qs[0]['userID__region_country']
            if not self.config_match_region(uid, country_id):
                return HttpResponse('Fail', status=500)

            UID = order_qs[0]['UID']
            # PayPal周期扣款首次扣款
            if billing_agreement.agreement_details.cycles_completed == '0':
                # 更新order表，paypal的商家交易号
                order_qs.update(status=1, updTime=nowTime, trade_no=paypal_transaction_id)
                PAY_LOGGER.info('{} PayPal周期扣款首次扣款成功'.format(UID))
                return HttpResponse('success')

            if order_qs[0]['addTime'] + 9200 > nowTime:  # 避免续费订单重复支付
                PAY_LOGGER.info('{} PayPal周期扣款失败---续费订单已创建'.format(UID))
                return HttpResponse('success')

            desc = order_qs[0]['desc']
            pay_type = order_qs[0]['payType']
            currency = order_qs[0]['currency']
            commodity_code = order_qs[0]['commodity_code']
            commodity_type = order_qs[0]['commodity_type']
            plan_id = order_qs[0]['plan_id']
            userid = order_qs[0]['userID__userID']
            username = order_qs[0]['userID__username']
            channel = order_qs[0]['channel']
            rank = order_qs[0]['rank']
            store_meal_qs = Store_Meal.objects.filter(id=rank).values("day", "bucket_id", "bucket__storeDay", "expire")
            if not store_meal_qs.exists():
                PAY_LOGGER.info('{} PayPal周期扣款失败---套餐数据不存在'.format(UID))
                return HttpResponse('fail', status=500)

            bucketId = store_meal_qs[0]['bucket_id']
            expire = store_meal_qs[0]['expire']
            ubqs = UID_Bucket.objects.filter(uid=UID).values("id", "bucket_id", "bucket__storeDay", "bucket__region",
                                                             "endTime", "use_status")

            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 = 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=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
                # 开通AI服务
                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)

                orderID = CommonService.createOrderID()
                store_meal_qs = Store_Meal.objects.filter(id=rank, lang__lang='cn', is_show=0).values('lang__title',
                                                                                                      'lang__content')
                if store_meal_qs.exists():
                    store_meal_name = store_meal_qs[0]['lang__title'] + '-' + store_meal_qs[0]['lang__content']
                else:
                    store_meal_name = '未知套餐'
                Order_Model.objects.create(orderID=orderID, UID=UID, channel=channel, userID_id=userid,
                                           desc=desc, payType=pay_type, payTime=nowTime,
                                           price=amount.get('total'),
                                           currency=order_qs[0]['currency'], addTime=nowTime,
                                           updTime=nowTime,
                                           pay_url='', isSelectDiscounts=0,
                                           commodity_code=commodity_code,
                                           commodity_type=commodity_type, rank_id=rank, paymentID='',
                                           coupon_id='', uid_bucket_id=uid_bucket_id, status=1,
                                           agreement_id=agreement_id, store_meal_name=store_meal_name,
                                           plan_id=plan_id, ai_rank_id=1, trade_no=paypal_transaction_id)

                # 如果存在序列号,消息提示用序列号
                device_name = CommonService.query_serial_with_uid(uid=UID)
                datetime = time.strftime("%Y-%m-%d", time.localtime())
                sys_msg_text_list = [
                    '温馨提示：尊敬的客户，您的' + device_name + '设备在' + datetime + '已成功续订云存套餐',
                    'Dear customer,you already subscribed the cloud storage package successfully for device ' + device_name + ' on ' + time.strftime(
                        "%b %dth,%Y", time.localtime())]

                if pay_type == 1:
                    lang = 'en'
                else:
                    lang = 'cn'
                CloudStorage.CloudStorageView().do_vod_msg_notice(UID, channel, userid, lang,
                                                                  sys_msg_text_list, 'SMS_219738485')

                # 更新agreement
                billing_agreement_update_attributes = [
                    {
                        "op": "replace",
                        "path": "/",
                        "value": {
                            "description": orderID,
                        }
                    }
                ]
                billing_agreement.replace(billing_agreement_update_attributes)
                PAY_LOGGER.info('{} PayPal周期扣款成功'.format(UID))
                return HttpResponse('success')
        except Exception as e:
            PAY_LOGGER.info('PayPal周期扣款异常: errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
            return HttpResponse('fail', status=500)

    @staticmethod
    def config_match_region(uid, country_id):
        """
        判断用户地区是否跟服务器地区匹配
        @param uid: uid
        @param country_id: 国家表id
        @return: bool
        """
        country_qs = CountryModel.objects.filter(id=country_id).values('region_id')
        # 不确定用户地区信息,默认美洲
        if not country_qs.exists() and CONFIG_INFO == CONFIG_EUR:
            PAY_LOGGER.info('PayPal周期扣款失败---不确定地区的用户请求欧洲服,uid:{},country_id:{}'.format(uid, country_id))
            return False

        region_id = country_qs[0]['region_id']
        PAY_LOGGER.info('uid{}的用户地区信息: country_id:{}, region_id:{}'.format(uid, country_id, region_id))
        if (CONFIG_INFO == CONFIG_US and region_id == 4) or (CONFIG_INFO == CONFIG_EUR and region_id != 4):
            PAY_LOGGER.info('PayPal周期扣款失败---服务器跟用户地区不匹配')
            return False
        return True

    def do_subscription_break_notify(self, request_dict, request, response):
        logger = logging.getLogger('pay')
        logger.info('--------进入订阅失败，付款失败，暂停--------')
        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('----主体信息----')
        logger.info(json_agreement_str)
        logger.info('----进入订阅失败头部信息----')
        logger.info(header)
        try:
            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)
            event_type = json_obj.get('event_type')
            summary = json_obj.get('summary')
            resource_type = json_obj.get('resource_type')
            paypal_transaction_id = paypal_body.get('id')
            amount = paypal_body.get('amount')

            # self.get_plan_desc('P-4CG284532S612303METMEINY')
            paypalrestsdk.configure(PAYPAL_CRD)
            response = paypalrestsdk.WebhookEvent.verify(
                transmission_id, transmission_time, PAYPAL_WEB_HOOK_ID_TWO, json_agreement_str, cert_url,
                transmission_sig, auth_algo)
            logger.info('----验证签名----')
            logger.info(response)
            if not response:
                return HttpResponse('Fail', status=500)
            event_type_code = 0
            billing_agreement_id = ''
            if event_type == 'PAYMENT.SALE.COMPLETED':
                event_type_code = 1
                billing_agreement_id = paypal_body.get('billing_agreement_id')
            elif event_type == 'PAYMENT.SALE.REVERSED':
                billing_agreement_id = paypal_body.get('billing_agreement_id')
                event_type_code = 2
            elif event_type == 'BILLING.SUBSCRIPTION.CANCELLED':
                billing_agreement_id = paypal_body.get('id')
                event_type_code = 3
            elif event_type == 'BILLING.SUBSCRIPTION.SUSPENDED':
                billing_agreement_id = paypal_body.get('id')
                event_type_code = 4
            elif event_type == 'BILLING.SUBSCRIPTION.PAYMENT.FAILED':
                billing_agreement_id = paypal_body.get('id')
                event_type_code = 5
            elif event_type == 'PAYMENT.SALE.REFUNDED':
                billing_agreement_id = paypal_body.get('billing_agreement_id')
                event_type_code = 6

            PaypalWebHookEventInsert = {
                'webhook_event_id': json_obj.get('id'),
                'resource_type': resource_type,
                'event_type': event_type_code,
                'summary': summary,
                'trade_no': paypal_transaction_id,
                'resource': json_agreement_str,
                'created_time': int(time.time()),
            }
            if not billing_agreement_id:
                # 记录钩子日志
                PaypalWebHookEvent.objects.create(**PaypalWebHookEventInsert)
                return HttpResponse('success')

            billing_agreement = paypalrestsdk.BillingAgreement.find(billing_agreement_id)
            # 记录钩子日志
            PaypalWebHookEventInsert['agreement_desc'] = repr(billing_agreement)
            PaypalWebHookEventInsert['agreement_id'] = billing_agreement_id
            PaypalWebHookEventInsert['orderID'] = billing_agreement.description
            PaypalWebHookEvent.objects.create(**PaypalWebHookEventInsert)
            return HttpResponse('success')

        except Exception as e:
            print(e)
            logger.info('----进入订阅失败----')
            logger.info('do_paypal_webhook_notify支付失败：----')
            logger.info("错误行数：{errLine}".format(errLine=e.__traceback__.tb_lineno))
            logger.info(repr(e))
            return HttpResponse('fail', status=500)

    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)
