Browse Source

内购循环扣款、VSees云存、圣诞折扣代码

linhaohong 8 months ago
parent
commit
cfbbf70599

+ 24 - 7
Controller/CloudStorage.py

@@ -10,6 +10,7 @@ import ssl
 from decimal import Decimal
 from itertools import groupby
 from operator import itemgetter
+from packaging import version
 from urllib.parse import quote, parse_qs, unquote
 
 import boto3
@@ -29,7 +30,7 @@ from Controller.PaymentCycle import Paypal
 from Model.models import Device_Info, Order_Model, Store_Meal, VodHlsModel, UID_Bucket, StsCrdModel, \
     ExperienceContextModel, Pay_Type, CDKcontextModel, Device_User, SysMsgModel, Unused_Uid_Meal, PromotionRuleModel, \
     VideoPlaybackTimeModel, CouponModel, VodBucketModel, VodHlsSummary, VodHlsTagType, UidSetModel, AiService, \
-    StsFrequency, InAppPurchasePackage
+    StsFrequency, InAppPurchasePackage, CouponCombo, CouponConfigModel
 from Object.AWS.AmazonS3Util import AmazonS3Util
 from Object.AWS.S3Email import S3Email
 from Object.AliPayObject import AliPayObject
@@ -184,12 +185,13 @@ class CloudStorageView(View):
         lang = request_dict.get('lang', 'en')
         is_ai = request_dict.get('is_ai', 0)
         app_type = request_dict.get('app_type', None)
+        ios_version = request_dict.get('ios_version', "")
         if not all([uid]):
             return response.json(444)
-        # 苹果内购,app_type:1
+        # 苹果内购,app_type:1 或 app_type:2
         is_ios = False
         if app_type is not None:
-            if int(app_type) == 1:
+            if int(app_type) == 1 or int(app_type) == 2:
                 is_ios = True
         is_ai = int(is_ai)
         now_time = int(time.time())
@@ -229,10 +231,15 @@ class CloudStorageView(View):
 
                 if CONFIG_INFO != CONFIG_CN:  # 国内生产环境不筛选像素 加载所有上架套餐
                     store_qs = store_qs.filter(Q(pixel_level=pixel_level))
-                if is_ios:
-                    store_qs = store_qs.filter(pay_type=5)
+
+                # 判断是否支持内购周期付款
+                if is_ios and version.parse(ios_version) >= version.parse("15.0"):
+                    store_qs = store_qs.filter(pay_type=5, app_type=app_type)
+                elif is_ios and version.parse(ios_version) < version.parse("15.0"):
+                    store_qs = store_qs.filter(pay_type=5, commodity_type=0, app_type=app_type)
                 else:
                     store_qs = store_qs.exclude(pay_type=5)
+
                 if uid not in ["VXJ267WU5NZ1S89H111A", "18SM4J9DYWB2AEG1111A",
                                "517J385BNUGP3CPP111A", "5Z1LZLK7D5Y6WKDE111A"] and CONFIG_INFO == CONFIG_TEST:
                     store_qs = store_qs.exclude(id=88)
@@ -248,8 +255,7 @@ class CloudStorageView(View):
                 store_qs = store_qs.filter(pay_type='10')  # 体验套餐不区分像素等级
 
             store_qs = store_qs.annotate(title=F('lang__title'), content=F('lang__content'),
-                                         new_title=F('lang__new_title'),
-                                         discount_content=F('lang__discount_content'))
+                                         new_title=F('lang__new_title'), discount_content=F('lang__discount_content'))
             store_qs = store_qs.order_by('sort').values("id", "title", "content", "price", "day", "currency",
                                                         "bucket__storeDay", "new_title",
                                                         "bucket__bucket", "bucket__area", "commodity_code",
@@ -278,6 +284,17 @@ class CloudStorageView(View):
                                 item['content'] = item['new_title'].get('1', '')
                             elif is_ai == 1:
                                 item['content'] = item['new_title'].get('2', '')
+                    if is_ios:
+                        if item['isCoupon']:
+                            item['isCoupon'] = False
+                        else:
+                            # 在列表删除这个套餐
+                            coupon_combo_ids = CouponCombo.objects.filter(combo_id=item['id']).values_list("coupon_id",
+                                                                                                           flat=True)
+                            coupon_config_qs = CouponConfigModel.objects.filter(id__in=coupon_combo_ids)
+                            if coupon_config_qs.exists():
+                                items_list.remove(item)
+
                 res_c = {'area': area, 'items': items_list}
                 res.append(res_c)
             # 是否促销

+ 599 - 176
Controller/InAppPurchaseController.py

@@ -7,6 +7,7 @@ import json
 import threading
 
 import requests
+from appstoreserverlibrary.models.Environment import Environment
 from appstoreserverlibrary.api_client import AppStoreServerAPIClient, GetTransactionHistoryVersion
 from appstoreserverlibrary.models.AccountTenure import AccountTenure
 from appstoreserverlibrary.models.ConsumptionRequest import ConsumptionRequest
@@ -20,24 +21,17 @@ from appstoreserverlibrary.models.PlayTime import PlayTime
 from appstoreserverlibrary.models.RefundPreference import RefundPreference
 from appstoreserverlibrary.models.UserStatus import UserStatus
 from appstoreserverlibrary.receipt_utility import ReceiptUtility
-from appstoreserverlibrary.models.HistoryResponse import HistoryResponse
-from appstoreserverlibrary.models.TransactionHistoryRequest import TransactionHistoryRequest, ProductType, Order
-from appstoreserverlibrary.signed_data_verifier import SignedDataVerifier
-
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives.serialization import load_pem_private_key
-
-from django.db.models import Q
 from django.views import View
 from django.http import HttpResponse
 
 from Ansjer.config import LOGGER, CONFIG_INFO, CONFIG_TEST, PAY_TYPE_IN_APP_PURCHASE, BASE_DIR, CONFIG_US
 from Controller.CheckUserData import DataValid
 from Model.models import Order_Model, Store_Meal, Device_Info, UID_Bucket, Unused_Uid_Meal, AiService, Device_User, \
-    SysMsgModel, OrderPayLog, InAppRefund
+    SysMsgModel, DeviceApplePackage, InAppPurchasePackage, InAppRefund, OrderPayLog, CouponModel
 from Object.AWS.S3Email import S3Email
 from Object.AliSmsObject import AliSmsObject
 from Object.AppleInAppPurchaseSubscriptionObject import InAppPurchase
+from Object.Enums.RedisKeyConstant import RedisKeyConstant
 from Object.RedisObject import RedisObject
 from Service.CommonService import CommonService
 
@@ -57,8 +51,14 @@ class InAppPurchaseView(View):
         return self.validation(request.POST, request, operation)
 
     def validation(self, request_dict, request, operation):
-        if operation == 'AppStoreServerNotifications':  # App Store服务器通知
-            return self.app_store_server_notifications(request)
+        if operation == 'AppStoreServerNotifications':  # App Store服务器通知(用于转发通知)
+            return self.app_store_server_notifications(request, request_dict)
+        elif operation == 'AppStoreServerNotificationsVsees':  # App Store服务器通知(用于转发通知)
+            return self.app_store_server_notifications_vsees(request, request_dict)
+        elif operation == 'vseesNotifications':
+            return self.vsees_notifications(request)
+        elif operation == 'serverNotifications':  # App Store服务器通知
+            return self.server_notifications(request)
         elif operation == 'putRefundOrder':  # App Store服务器通知
             return self.put_refund_order()
         token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request)
@@ -78,13 +78,22 @@ class InAppPurchaseView(View):
         @return: response
         """
         receipt = request_dict.get('receipt', None)
+        transaction_identifier = request_dict.get('transactionIdentifier', "")
+        original_transaction_identifier = request_dict.get('originalTransactionIdentifier', "")
         order_id = request_dict.get('orderID', None)
         uid = request_dict.get('uid', None)
         lang = request_dict.get('lang', 'en')
         channel = request_dict.get('channel', None)
-        logger.info(f"receipt: {receipt}, 订单orderId: {order_id}, uid: {uid}")
+        app_type = request_dict.get('app_type', 1)
 
-        if not all([receipt, uid, channel, order_id]):
+        logger.info(
+            f"苹果内购认证交易订单orderID:{order_id},"
+            f"transaction_id: {transaction_identifier},"
+            f"original_transaction_id: {original_transaction_identifier},"
+            f"receipt: {receipt}, app_type: {app_type}"
+        )
+
+        if not all([uid, channel, order_id]):
             return response.json(444)
 
         # redis加锁,防止订单重复
@@ -96,10 +105,21 @@ class InAppPurchaseView(View):
         redis_obj.CONN.expire(redis_key, 60)
 
         try:
-            order_qs = Order_Model.objects.filter(orderID=order_id, UID=uid).values("rank_id", "transaction_id")
+            # 检查商品id是否正确
+            app_type = int(app_type)
+            if app_type == 1:
+                bundle_id = "com.ansjer.zccloud"
+            elif app_type == 2:
+                bundle_id = "com.cloudlife.commissionf"
+            else:
+                return response.json(444, "app_type不存在")
 
+            # 验证订单是否存在
+            order_qs = Order_Model.objects.filter(orderID=order_id, UID=uid, app_type=app_type).values("rank_id",
+                                                                                                       "transaction_id",
+                                                                                                       "coupon_id")
             if not order_qs.exists():
-                return response.json(173, "订单不存在")
+                return response.json(173)
             if order_qs[0]["transaction_id"]:
                 return response.json(0)
             if UID_Bucket.objects.filter(orderId=order_id).exists():
@@ -107,23 +127,22 @@ class InAppPurchaseView(View):
             if Unused_Uid_Meal.objects.filter(order_id=order_id).exists():
                 return response.json(0)
 
-            # 从交易信息中获取product_id
-            key_path = '{}/Ansjer/file/in_app_purchase/SubscriptionKey_N42WMFCV6A.p8'.format(BASE_DIR)
-            with open(key_path, 'rb') as file:
-                # 读取文件内容
-                private_key = file.read()
+            # 实例化订阅类
+            in_app_purchase = InAppPurchase(bundle_id=bundle_id)
 
-            key_id = 'N42WMFCV6A'
-            issuer_id = '69a6de8c-789b-47e3-e053-5b8c7c11a4d1'
-            bundle_id = 'com.ansjer.zccloud'
-            environment = ENV
-
-            client = AppStoreServerAPIClient(private_key, key_id, issuer_id, bundle_id, environment)
-            receipt_util = ReceiptUtility()
-
-            transaction_id = receipt_util.extract_transaction_id_from_app_receipt(receipt)
-
-            if transaction_id is None:
+            # ReceiptUtility 用于解析收据为transaction_id
+            receipt_util = in_app_purchase.receipt_util
+            # AppStoreServerAPIClient 用于查询交易信息
+            client = in_app_purchase.client
+            # SignedDataVerifier 用于解析查询到的交易信息
+            signed_data_verifier = in_app_purchase.verifier
+
+            # 解析收据(循环扣款时不需要这一步, 直接获取transaction_id)
+            transaction_id = transaction_identifier
+            if transaction_identifier == "":
+                transaction_id = receipt_util.extract_transaction_id_from_app_receipt(receipt)
+            if not transaction_id:
+                logger.info(f"苹果内购认证交易订单orderID:{order_id}, 没有transaction_id")
                 pay_result_url = CommonService.get_payment_status_url(lang, 'fail')
                 return response.json(0, {'url': pay_result_url})
             logger.info(f"苹果内购认证交易订单orderID:{order_id}, transaction_id:{transaction_id}, 时间戳: {int(time.time())}")
@@ -133,8 +152,8 @@ class InAppPurchaseView(View):
                                        created_time=int(time.time()), updated_time=int(time.time()),
                                        access_result="SUCCESS")
 
-            transaction_info = ""
             # 查询交易信息
+            transaction_info = ""
             attempts = 0
             while attempts < 6:
                 try:
@@ -148,89 +167,97 @@ class InAppPurchaseView(View):
                                                    created_time=int(time.time()), updated_time=int(time.time()),
                                                    access_result="ERROR")
                         return response.json(5)
-                    logger.info(f"订单orderId:{order_id}, transaction_id:{transaction_id}, 第{attempts}次获取支付信息超时")
+                    logger.info(
+                        f"订单orderId:{order_id}, transaction_id:{transaction_id}, 第{attempts}次获取支付信息超时")
 
-            logger.info(f"订单orderId:{order_id}, transaction_id:{transaction_id}, 成功获取支付信息, 时间戳: {int(time.time())}")
             signed_transaction_info = transaction_info.signedTransactionInfo
-
-            root_certificates = []
-            for cert_name in [
-                'AppleIncRootCertificate.cer', 'AppleComputerRootCertificate.cer',
-                'AppleRootCA-G2.cer', 'AppleRootCA-G3.cer'
-            ]:
-                cert_path = '{}/Ansjer/file/in_app_purchase/{}'.format(BASE_DIR, cert_name)
-                with open(cert_path, 'rb') as file:
-                    # 读取文件内容
-                    root_certificates.append(file.read())
-
-            enable_online_checks = True
-            app_apple_id = 1355964934  # 生产环境必需
-            signed_data_verifier = SignedDataVerifier(
-                root_certificates, enable_online_checks, environment, bundle_id, app_apple_id)
-
+            # 解析交易信息
             payload = signed_data_verifier.verify_and_decode_signed_transaction(signed_transaction_info)
 
-            product_id = None
-
-            if payload and payload.productId:
-                product_id = payload.productId
-
+            # 获取交易的商品id
+            product_id = payload.productId if payload and payload.productId else None
             if not product_id:
                 logger.info(f"苹果内购认证交易订单orderID:{order_id}, product_id获取失败")
                 pay_result_url = CommonService.get_payment_status_url(lang, 'fail')
                 return response.json(0, {'url': pay_result_url})
 
-            now_time = int(time.time())
+            in_app_purchase_package_qs = InAppPurchasePackage.objects.filter(product_id=product_id)
+            if not in_app_purchase_package_qs.exists():
+                logger.info(f"苹果内购认证交易订单orderID:{order_id}, InAppPurchasePackage表未查询到product_id")
+                return response.json(173, "内购商品id不存在")
 
+            # 验证套餐是否存在
             store_qs = Store_Meal.objects.filter(id=order_qs[0]['rank_id']).values(
                 'id', 'currency', 'price', 'lang__content', 'day', 'commodity_type', 'lang__title', 'expire',
                 'commodity_code', 'discount_price', 'bucket_id', 'bucket__mold', 'cycle_config_id', 'is_ai')
+
             if not store_qs.exists():
-                return response.json(173, "套餐不存在")
-
-            bucket_id = store_qs[0]['bucket_id']
-            is_ai = store_qs[0]['is_ai']
-            expire = store_qs[0]['expire']
-            end_time = CommonService.calcMonthLater(expire)
-
-            # 查询设备是否已开过云存
-            use_flag = True
-            uid_bucket_qs = UID_Bucket.objects.filter(uid=uid). \
-                values('id', 'bucket_id', 'bucket__region', 'endTime', 'use_status')
-            if uid_bucket_qs.exists():
-                uid_bucket = uid_bucket_qs.first()
-                uid_bucket_id = uid_bucket['id']
-                # 叠加相同套餐的过期时间
-                if uid_bucket['use_status'] == 1 and uid_bucket['endTime'] > now_time:
-                    Unused_Uid_Meal.objects.create(
-                        uid=uid, channel=channel, addTime=now_time, order_id=order_id, expire=expire, is_ai=is_ai,
-                        bucket_id=bucket_id)
-                    UID_Bucket.objects.filter(id=uid_bucket_id).update(has_unused=1)
-                    use_flag = False
-                # 更新套餐的过期时间
-                else:
-                    UID_Bucket.objects.filter(id=uid_bucket_id).update(
-                        channel=channel, bucket_id=bucket_id, endTime=end_time, updateTime=now_time, use_status=1,
-                        orderId=order_id)
-            else:
-                uid_bucket = UID_Bucket.objects.create(
-                    uid=uid, channel=channel, bucket_id=bucket_id, endTime=end_time, use_status=1, orderId=order_id,
-                    addTime=now_time, updateTime=now_time)
-                uid_bucket_id = uid_bucket.id
-
-            # 开通AI服务
-            if is_ai and use_flag:
-                ai_service = AiService.objects.filter(uid=uid, channel=channel)
-                # 有正在使用的套餐,叠加套餐时间,否则创建
-                if ai_service.exists():
-                    ai_service.update(updTime=now_time, use_status=1, orders_id=order_id, endTime=end_time)
+                return response.json(173, "云存套餐不存在")
+
+            # 验证内购套餐是否存在
+            in_app_purchase_package_qs = InAppPurchasePackage.objects.filter(product_id=product_id)
+            if not in_app_purchase_package_qs.exists():
+                return response.json(173, "内购套餐不存在")
+
+            # 循环扣款
+            if original_transaction_identifier != "" and in_app_purchase_package_qs[0].package_type == 1:
+                device_apple_package_qs = DeviceApplePackage.objects.filter(
+                    original_transaction_id=original_transaction_identifier)
+                if device_apple_package_qs.exists():
+                    # 第一种情况: 套餐已过期再次订阅
+                    if device_apple_package_qs[0].uid == uid and device_apple_package_qs[0].subscription_status == 2:
+                        # 使用App Store服务器通知接口订阅
+                        Order_Model.objects.filter(orderID=order_id).delete()
+                        pay_result_url = CommonService.get_payment_status_url(lang, 'success')
+                        return response.json(0, {'url': pay_result_url})
+
+                    # 第二种情况: 套餐未过期已取消再次订阅
+                    elif device_apple_package_qs[0].uid == uid and device_apple_package_qs[0].subscription_status == 3:
+                        # 使用App Store服务器通知接口修改订阅状态
+                        Order_Model.objects.filter(orderID=order_id).delete()
+                        pay_result_url = CommonService.get_payment_status_url(lang, 'success')
+                        return response.json(0, {'url': pay_result_url})
+
+                    # 第三种情况: 首次订阅
+                    elif device_apple_package_qs[0].uid == uid and device_apple_package_qs[0].subscription_status == 0:
+                        logger.info(f"苹果内购认证交易订单orderID:{order_id}, 用户首次订阅")
+
+                    else:
+                        logger.info(
+                            f"错误调用此借口,orderID:{order_id}, uid:{uid}, 订阅状态:{device_apple_package_qs[0].subscription_status}")
+                        pay_result_url = CommonService.get_payment_status_url(lang, 'fail')
+                        return response.json(0, {'url': pay_result_url})
+
                 else:
-                    AiService.objects.create(
-                        uid=uid, channel=channel, detect_status=1, use_status=1, orders_id=order_id,
-                        addTime=now_time, updTime=now_time, endTime=end_time)
+                    return response.json(173, "内购套餐未分配")
 
-            order_qs.update(status=1, uid_bucket_id=uid_bucket_id, transaction_id=transaction_id, create_vod=1,
-                            payTime=int(time.time()), updTime=int(time.time()))
+            # 设备开通云存
+            now_time = int(time.time())
+            uid_bucket_id = cls.enable_cloud(channel, now_time, order_id, store_qs, uid)
+
+            if order_qs[0]["coupon_id"]:
+                c_id = order_qs[0]["coupon_id"]
+                key_coupon = RedisKeyConstant.COUPON_ID_LOCK.value + c_id
+                redis_obj.del_data(key_coupon)
+                CouponModel.objects.filter(id=c_id).update(use_status=2, update_time=now_time)
+
+
+            # 修改订阅状态
+            if payload.rawType == "Auto-Renewable Subscription":
+                original_transaction_id = payload.originalTransactionId
+                in_app_purchase_package = in_app_purchase_package_qs.values('id').first()
+                package_id = in_app_purchase_package['id']
+                DeviceApplePackage.objects.filter(userID=user_id, uid=uid, package_id=package_id).update(
+                    subscription_status=1, original_transaction_id=original_transaction_id,
+                )
+                order_qs.update(status=1, uid_bucket_id=uid_bucket_id,
+                                transaction_id=transaction_id, create_vod=1,
+                                payTime=now_time, updTime=now_time,
+                                original_transaction_id=original_transaction_id)
+            else:
+                order_qs.update(status=1, uid_bucket_id=uid_bucket_id,
+                                transaction_id=transaction_id, create_vod=1,
+                                payTime=now_time, updTime=now_time)
 
             # 构建云存套餐消息
             sys_msg_text_list = cls.cloud_storage_message(uid)
@@ -249,7 +276,6 @@ class InAppPurchaseView(View):
                                        access_result="SUCCESS")
 
             return response.json(0, {'url': pay_result_url})
-
         except Exception as e:
             redis_obj.del_data(redis_key)
             logger.info('苹果内购认证交易接口异常:{}'.
@@ -277,6 +303,48 @@ class InAppPurchaseView(View):
             format(device_name, time.strftime('%b %dth,%Y', time.localtime()))]
         return sys_msg_text_list
 
+    @classmethod
+    def enable_cloud(cls, channel, now_time, order_id, store_qs, uid):
+        bucket_id = store_qs[0]['bucket_id']
+        is_ai = store_qs[0]['is_ai']
+        expire = store_qs[0]['expire']
+        end_time = CommonService.calcMonthLater(expire)
+        # 查询设备是否已开过云存
+        use_flag = True
+        uid_bucket_qs = UID_Bucket.objects.filter(uid=uid). \
+            values('id', 'bucket_id', 'bucket__region', 'endTime', 'use_status')
+        if uid_bucket_qs.exists():
+            uid_bucket = uid_bucket_qs.first()
+            uid_bucket_id = uid_bucket['id']
+            # 有正在使用的套餐,创建为未使用套餐
+            if uid_bucket['use_status'] == 1 and uid_bucket['endTime'] > now_time:
+                Unused_Uid_Meal.objects.create(
+                    uid=uid, channel=channel, addTime=now_time, order_id=order_id, expire=expire, is_ai=is_ai,
+                    bucket_id=bucket_id)
+                UID_Bucket.objects.filter(id=uid_bucket_id).update(has_unused=1)
+                use_flag = False
+            # 无正在使用套餐,直接使用套餐
+            else:
+                UID_Bucket.objects.filter(id=uid_bucket_id).update(
+                    channel=channel, bucket_id=bucket_id, endTime=end_time, updateTime=now_time, use_status=1,
+                    orderId=order_id)
+        else:
+            uid_bucket = UID_Bucket.objects.create(
+                uid=uid, channel=channel, bucket_id=bucket_id, endTime=end_time, use_status=1, orderId=order_id,
+                addTime=now_time, updateTime=now_time)
+            uid_bucket_id = uid_bucket.id
+        # 开通AI服务
+        if is_ai and use_flag:
+            ai_service = AiService.objects.filter(uid=uid, channel=channel)
+            # 有正在使用的套餐,叠加套餐时间,否则创建
+            if ai_service.exists():
+                ai_service.update(updTime=now_time, use_status=1, orders_id=order_id, endTime=end_time)
+            else:
+                AiService.objects.create(
+                    uid=uid, channel=channel, detect_status=1, use_status=1, orders_id=order_id,
+                    addTime=now_time, updTime=now_time, endTime=end_time)
+        return uid_bucket_id
+
     @classmethod
     def do_vod_msg_notice(cls, uid, user_id, lang, sys_msg_text_list):
         """
@@ -340,38 +408,429 @@ class InAppPurchaseView(View):
         ali_sms.send_code_sms_cloud(phone=phone, params=params, sign_name=sign_ms, temp_msg=temp_msg)
 
     @classmethod
-    def app_store_server_notifications(cls, request):
-        logger.info('App Store服务器通知请求类型:{}'.format(request.method))
-        logger.info('App Store服务器通知参数:{}'.format(request.POST))
-        logger.info('App Store服务器通知请求body:{}'.format(request.body))
+    def app_store_server_notifications(cls, request, request_dict):
+        logger = logging.getLogger('apple_pay')
+        if request.method != 'POST':
+            logger.info(f'App Store服务器通知不是post请求, 参数{request_dict}')
+            return HttpResponse(status=400)
+        try:
+            request_data = json.loads(request.body)
+        except json.JSONDecodeError:
+            logger.info('无法解析请求体为JSON')
+            return HttpResponse(status=400)
+
+        request_data['bundleId'] = 'com.ansjer.zccloud'
+        updated_request_body = json.dumps(request_data)
+
+        if CONFIG_INFO == CONFIG_TEST:
+            logger.info('测试环境, App Store服务器通知发送到测试服')
+            response_test = requests.post(url="https://test.zositechc.cn/inAppPurchase/serverNotifications",
+                                          json=updated_request_body)
+            return HttpResponse(status=response_test.status_code)
+        response_us = requests.post(url="https://www.dvema.com/inAppPurchase/serverNotifications",
+                                    json=updated_request_body)
+        status_code = response_us.status_code
+        if status_code != 200:
+            response_eu = requests.post(url="https://api.zositeche.com/inAppPurchase/serverNotifications",
+                                        json=updated_request_body)
+            status_code = response_eu.status_code
+        if status_code == 200:
+            return HttpResponse(status=200)
+        return HttpResponse(status=400)
+
+    @classmethod
+    def server_notifications(cls, request):
+        try:
+            logger.info('App Store服务器通知请求类型:{}'.format(request.method))
+            logger.info('App Store服务器通知参数:{}'.format(request.POST))
+            logger.info('App Store服务器通知请求body:{}'.format(request.body))
+            payload = json.loads(json.loads(request.body))
+            logger.info('App Store服务器通知payload:{}'.format(payload))
+            # 获取 signedPayload
+            signed_payload = payload.get('signedPayload')
+            bundle_id = payload.get('bundleId')
+            if not signed_payload:
+                return HttpResponse(status=400)
+            if bundle_id == "com.ansjer.zccloud":
+                app_type = 1
+            else:
+                app_type = 2
+
+            in_app_purchase_obj = InAppPurchase(bundle_id=bundle_id)
+            # AppStoreServerAPIClient 用于查询交易信息
+            client = in_app_purchase_obj.client
+            # SignedDataVerifier 用于解析查询到的交易信息
+            signed_data_verifier = in_app_purchase_obj.verifier
+
+            # 验证签名并解码 payload
+            decoded_payload = signed_data_verifier.verify_and_decode_notification(signed_payload)
+
+            logger.info(f"App Store服务器通知解码后decoded_payload:{decoded_payload}")
+            raw_notification_type = str(decoded_payload.rawNotificationType)
+            raw_subtype = str(decoded_payload.rawSubtype)
+            logger.info(f"App Store服务器通知, 大类型{raw_notification_type}, 小类型{raw_subtype}")
+
+            if str(decoded_payload.rawNotificationType) == "DID_RENEW":
+                # 续订
+                decoded_transaction_information = signed_data_verifier.verify_and_decode_signed_transaction(
+                    decoded_payload.data.signedTransactionInfo)
+                # originalTransactionId 原始购买的交易标识符
+                original_transaction_id = decoded_transaction_information.originalTransactionId
+                transaction_id = decoded_transaction_information.transactionId
+                logger.info(f"App Store服务器通知, 续订originalTransactionId{original_transaction_id}")
+                if not original_transaction_id:
+                    logger.info(f"App Store服务器通知 originalTransactionId原始购买的交易标识符为空, 返回状态 400")
+                    return HttpResponse(status=400)
+                ord_order = Order_Model.objects.filter(original_transaction_id=original_transaction_id).order_by(
+                    '-addTime').values("channel", "UID", "payType", "userID_id", "rank_id")
+                if not ord_order.exists():
+                    logger.info(
+                        f"App Store服务器通知, 未查询到旧订单信息, originalTransactionId:{original_transaction_id}, 返回状态 400")
+                    return HttpResponse(status=400)
+
+                channel = ord_order[0]["channel"]
+                uid = ord_order[0]["UID"]
+                pay_type = ord_order[0]["payType"]
+                user_id = ord_order[0]["userID_id"]
+
+                store_qs = Store_Meal.objects.filter(id=ord_order[0]["rank_id"]). \
+                    values(
+                    'id', 'currency', 'price', 'lang__content', 'day', 'commodity_type', 'lang__title',
+                    'expire', 'lang__lang',
+                    'commodity_code', 'discount_price', 'bucket_id', 'bucket__mold', 'cycle_config_id', 'is_ai')
+
+                if not store_qs.exists():
+                    logger.info(f"App Store服务器通知云存套餐不存在, 返回状态 400")
+                    return HttpResponse(status=400)
+
+                # 解决云存充值成功, 由于一些原因返回500 导致苹果未扣款的问题
+                if Order_Model.objects.filter(transaction_id=transaction_id, status=1).exists():
+                    logger.info(f"App Store服务器通知云存续订订单已存在, transactionId:{transaction_id} 返回状态 200")
+                    return HttpResponse(status=200)
+
+                order_id = CommonService.createOrderID()
+                rank_id = store_qs[0]['id']
+                currency = store_qs[0]['currency']
+                price = store_qs[0]['price']
+                is_ai = store_qs[0]['is_ai']
+                content = store_qs[0]['lang__content']
+                commodity_code = store_qs[0]['commodity_code']
+                commodity_type = store_qs[0]['commodity_type']
+                lang = store_qs[0]['lang__lang']
+                order_type = 1 if is_ai else 0
+                now_time = int(time.time())
+
+                store_meal_qs = Store_Meal.objects.filter(id=rank_id, 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 = Order_Model.objects.create(
+                    orderID=order_id, UID=uid, channel=channel, userID_id=user_id, desc=content,
+                    payType=pay_type, payTime=now_time, price=price, currency=currency, addTime=now_time,
+                    updTime=now_time, order_type=order_type, commodity_code=commodity_code,
+                    commodity_type=commodity_type, rank_id=rank_id, ai_rank_id=1, status=1,
+                    store_meal_name=store_meal_name, app_type=app_type
+                )
+
+                # 充值云存套餐
+                uid_bucket_id = cls.enable_cloud(channel, now_time, order_id, store_qs, uid)
+
+                # 修改订单信息
+                order.uid_bucket_id = uid_bucket_id
+                order.transaction_id = transaction_id
+                order.original_transaction_id = original_transaction_id
+                order.save()
+
+                # 构建云存套餐消息
+                sys_msg_text_list = cls.cloud_storage_message(uid)
+                cls.do_vod_msg_notice(uid, user_id, lang, sys_msg_text_list)
+                return HttpResponse(status=200)
+
+            elif str(decoded_payload.rawNotificationType) == "SUBSCRIBED":
+                # 处理订阅 ---> 首次充值逻辑写在了认证交易
+                if decoded_payload.rawSubtype == "RESUBSCRIBE":
+                    decoded_transaction_information = signed_data_verifier.verify_and_decode_signed_transaction(
+                        decoded_payload.data.signedTransactionInfo)
+                    # originalTransactionId 原始购买的交易标识符
+                    original_transaction_id = decoded_transaction_information.originalTransactionId
+                    transaction_id = decoded_transaction_information.transactionId
+                    app_account_token = decoded_transaction_information.appAccountToken
+                    app_account_token = json.loads(app_account_token)
+                    logger.info(
+                        f"App Store服务器通知,再次订阅originalTransactionId原始购买的交易标识符{original_transaction_id}")
+                    if not original_transaction_id:
+                        logger.info(f"App Store服务器通知 originalTransactionId原始购买的交易标识符为空, 返回状态 400")
+                        return HttpResponse(status=400)
+                    # 查旧订单消息
+                    ord_order_qs = Order_Model.objects.filter(original_transaction_id=original_transaction_id)
+                    if not ord_order_qs.exists():
+                        logger.info(f"App Store服务器通知未查询到旧订单信息, originalTransactionId:{original_transaction_id}, 返回状态 400")
+                        return HttpResponse(status=400)
+
+                    # 解决云存充值成功, 由于一些原因返回500 导致苹果未扣款的问题
+                    if Order_Model.objects.filter(transaction_id=transaction_id, status=1).exists():
+                        logger.info(
+                            f"App Store服务器通知云存续订订单已存在, transactionId:{transaction_id} 返回状态 200")
+                        return HttpResponse(status=200)
+
+                    ord_order = ord_order_qs.order_by('-addTime').values("channel", "UID", "payType", "userID_id")
+                    channel = ord_order[0]["channel"]
+                    uid = ord_order[0]["UID"]
+                    pay_type = ord_order[0]["payType"]
+                    user_id = ord_order[0]["userID_id"]
+
+                    new_user_id = app_account_token["user_id"]
+                    if new_user_id != user_id:
+                        uid = app_account_token["UID"]
+                        user_id = new_user_id
+
+                    # 用产品id找到使用的套餐
+                    product_id = decoded_transaction_information.productId
+                    rank_id = InAppPurchasePackage.objects.filter(product_id=product_id).values("rank")[0]["rank"]
+                    store_qs = Store_Meal.objects.filter(id=rank_id). \
+                        values(
+                        'id', 'currency', 'price', 'lang__content', 'day', 'commodity_type', 'lang__title',
+                        'expire', 'lang__lang',
+                        'commodity_code', 'discount_price', 'bucket_id', 'bucket__mold', 'cycle_config_id', 'is_ai')
+
+                    if not store_qs.exists():
+                        logger.info(f"App Store服务器通知云存套餐不存在, 返回状态 400")
+                        return HttpResponse(status=400)
+
+                    order_id = CommonService.createOrderID()
+                    rank_id = store_qs[0]['id']
+                    currency = store_qs[0]['currency']
+                    price = store_qs[0]['price']
+                    is_ai = store_qs[0]['is_ai']
+                    content = store_qs[0]['lang__content']
+                    commodity_code = store_qs[0]['commodity_code']
+                    commodity_type = store_qs[0]['commodity_type']
+                    lang = store_qs[0]['lang__lang']
+                    order_type = 1 if is_ai else 0
+                    now_time = int(time.time())
+
+                    store_meal_qs = Store_Meal.objects.filter(id=rank_id, 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 = Order_Model.objects.create(
+                        orderID=order_id, UID=uid, channel=channel, userID_id=user_id, desc=content,
+                        payType=pay_type, payTime=now_time, price=price, currency=currency, addTime=now_time,
+                        updTime=now_time, order_type=order_type, commodity_code=commodity_code,
+                        commodity_type=commodity_type, rank_id=rank_id, ai_rank_id=1, status=1,
+                        store_meal_name=store_meal_name, app_type=app_type
+                    )
+
+                    # 充值云存套餐
+                    uid_bucket_id = cls.enable_cloud(channel, now_time, order_id, store_qs, uid)
+
+                    # 修改订单信息
+                    order.uid_bucket_id = uid_bucket_id
+                    order.transaction_id = transaction_id
+                    order.original_transaction_id = original_transaction_id
+                    order.save()
+
+                    DeviceApplePackage.objects.filter(userID=user_id, uid=uid).update(subscription_status=1,
+                                                                                      update_time=int(time.time()))
+
+                    # 构建云存套餐消息
+                    sys_msg_text_list = cls.cloud_storage_message(uid)
+
+                    cls.do_vod_msg_notice(uid, user_id, lang, sys_msg_text_list)
+                return HttpResponse(status=200)
+
+            elif str(decoded_payload.rawNotificationType) == "EXPIRED":
+                # 一种通知类型,与其子类型一起表示订阅已过期。如果subtype为
+                # VOLUNTARY(自愿),则表示订阅在用户禁用订阅续订后过期。如果subtype是
+                # BILLING_RETRY(计费重试),则表示订阅过期,因为计费重试期结束时没有成功的计费交易。如果subtype为
+                # PRICE_INCREASE,则表示订阅已过期,因为客户不同意需要客户同意的价格上涨。如果subtype为
+                # PRODUCT_NOT_FOR_SALE,则表示订阅已过期,因为在订阅尝试续订时,产品已不可购买。
+                # 没有子类型的通知表示订阅因其他原因过期。
+                decoded_transaction_information = signed_data_verifier.verify_and_decode_signed_transaction(
+                    decoded_payload.data.signedTransactionInfo)
+                # originalTransactionId 原始购买的交易标识符
+                original_transaction_id = decoded_transaction_information.originalTransactionId
+                if not original_transaction_id:
+                    logger.info(f"App Store服务器通知 originalTransactionId原始购买的交易标识符为空, 返回状态 400")
+                    return HttpResponse(status=400)
+                device_apple_package_qs = DeviceApplePackage.objects.filter(
+                    original_transaction_id=original_transaction_id)
+                if not device_apple_package_qs.exists():
+                    return HttpResponse(status=400)
+                device_apple_package_qs.update(subscription_status=2, update_time=int(time.time()))
+
+            elif str(decoded_payload.rawNotificationType) == "CONSUMPTION_REQUEST":
+                # 一种通知类型,指示客户发起了消费型 App 内购买项目或自动续期订阅的退款请求,并且 App Store 要求您提供消费数据。有关详细信息,请参阅发送消耗信息。
+                decoded_transaction_information = signed_data_verifier.verify_and_decode_signed_transaction(
+                    decoded_payload.data.signedTransactionInfo)
+                transaction_id = decoded_transaction_information.transactionId
+                app_account_token = decoded_transaction_information.appAccountToken
+                if not app_account_token:
+                    app_account_token = ""
+                orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
+                if not orders_qs.exists():
+                    return HttpResponse(status=400)
+                orderID = orders_qs[0].orderID
+                uid = orders_qs[0].UID
+                now_time = int(time.time())
+                put_time = now_time + 11.5 * 60 * 60
+                in_app_refund_qs = InAppRefund.objects.filter(transaction_id=transaction_id)
+                if in_app_refund_qs.exists():
+                    in_app_refund_qs.update(refund_progress=0, updated_time=now_time,
+                                            put_time=put_time, app_account_token=app_account_token)
+                InAppRefund.objects.create(transaction_id=transaction_id, orderID=orderID,
+                                           uid=uid, app_type=app_type, created_time=now_time,
+                                           updated_time=now_time, put_time=put_time,
+                                           app_account_token=app_account_token)
+                return HttpResponse(status=200)
+
+            elif str(decoded_payload.rawNotificationType) == "DID_CHANGE_RENEWAL_STATUS":
+                decoded_transaction_information = signed_data_verifier.verify_and_decode_signed_transaction(
+                    decoded_payload.data.signedTransactionInfo)
+                original_transaction_id = decoded_transaction_information.originalTransactionId
+                if not original_transaction_id:
+                    logger.info(f"App Store服务器通知 originalTransactionId原始购买的交易标识符为空, 返回状态 400")
+                    return HttpResponse(status=400)
+                if decoded_payload.rawSubtype == "AUTO_RENEW_ENABLED":
+                    # 自动续订被开启
+                    device_apple_package_qs = DeviceApplePackage.objects.filter(
+                        original_transaction_id=original_transaction_id)
+                    if not device_apple_package_qs.exists():
+                        return HttpResponse(status=400)
+                    device_apple_package_qs.update(subscription_status=1, update_time=int(time.time()))
+                else:
+                    # 自动续订被禁用
+                    device_apple_package_qs = DeviceApplePackage.objects.filter(
+                        original_transaction_id=original_transaction_id)
+                    if not device_apple_package_qs.exists():
+                        return HttpResponse(status=400)
+                    device_apple_package_qs.update(subscription_status=3, update_time=int(time.time()))
+
+            elif str(decoded_payload.rawNotificationType) == "REFUND":
+                # 一种通知类型,表示 App Store 成功退还了消耗性应用内购买、非消耗性应用内购买、自动续订或不可续订的交易。
+                # revocationDate 包含退款交易的时间戳。originalTransactionId 和 productId 用于标识原始交易和产品。revocationReason 包含原因。
+                # 要请求客户所有退款交易的列表,请参阅 App Store 服务器 API 中的获取退款历史记录。
+                decoded_transaction_information = signed_data_verifier.verify_and_decode_signed_transaction(
+                    decoded_payload.data.signedTransactionInfo)
+                transaction_id = decoded_transaction_information.transactionId
+                logger.info('App Store服务器通知退款, transaction_id:{}'.format(transaction_id))
+                orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
+                if not orders_qs.exists():
+                    return HttpResponse(status=400)
+                orders_qs.update(status=5, updTime=int(time.time()))
+                orderID = orders_qs[0].orderID
+                uid = orders_qs[0].UID
+                uid_bucket_qs = UID_Bucket.objects.filter(uid=uid, orderId=orderID, use_status=1,
+                                                          endTime__gt=int(time.time()))
+                unused_uid_meal_qs = Unused_Uid_Meal.objects.filter(order_id=orderID)
+                ai_service_qs = AiService.objects.filter(uid=uid, orders=orderID, use_status=1,
+                                                         endTime__gt=int(time.time()))
+                if unused_uid_meal_qs.exists():
+                    unused_uid_meal_qs.delete()
+                if uid_bucket_qs.exists():
+                    uid_bucket_qs.update(status=0, use_status=2, endTime=int(time.time()),
+                                         updateTime=int(time.time()))
+                if ai_service_qs.exists():
+                    ai_service_qs.update(detect_status=0, use_status=2, endTime=int(time.time()),
+                                         updTime=int(time.time()))
+                    # 关闭ai
+                    msg = {'commandType': 'AIDisable'}
+                    thing_name = CommonService.query_serial_with_uid(uid)  # 存在序列号则为使用序列号作为物品名
+                    topic_name = 'ansjer/generic/{}'.format(thing_name)
+                    req_success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
+                    logger.info(f'App Store服务器通知用户退款, 关闭AI:{req_success}')
+                InAppRefund.objects.filter(transaction_id=transaction_id).update(updated_time=int(time.time()),
+                                                                                 refund_progress=2)
+                return HttpResponse(status=200)
+
+            elif str(decoded_payload.rawNotificationType) == "REFUND_DECLINED":
+                # 一种通知类型,表示 App Store 由于客户提出的争议而撤销了先前批准的退款。如果您的应用程序因相关退款而撤销了内容或服务,则需要恢复这些内容或服务。
+                # 此通知类型可适用于任何应用程序内购买类型:消耗品、非消耗品、不可续订订阅和自动续订订阅。对于自动续订,当 App Store 撤销退款时,续订日期保持不变。
+                decoded_transaction_information = signed_data_verifier.verify_and_decode_signed_transaction(
+                    decoded_payload.data.signedTransactionInfo)
+                transaction_id = decoded_transaction_information.transactionId
+                logger.info(
+                    'App Store服务器通知,撤销了批准的退款,不恢复套餐,手动处理 transaction_id:{}'.format(transaction_id))
+
+            elif str(decoded_payload.rawNotificationType) == "REFUND_DECLINED":
+                decoded_transaction_information = signed_data_verifier.verify_and_decode_signed_transaction(
+                    decoded_payload.data.signedTransactionInfo)
+                transaction_id = decoded_transaction_information.transactionId
+                orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
+                if not orders_qs.exists():
+                    return HttpResponse(status=400)
+                InAppRefund.objects.filter(transaction_id=transaction_id).update(refund_progress=3)
+
+            else:
+                logger.info(f"App Store服务器通知decoded_payload.rawNotificationType 未处理")
+                return HttpResponse(status=200)
+
+        except Exception as e:
+            logger.info('App Store服务器通知异常:{}'.
+                        format('error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e))))
+            return HttpResponse(status=500)
+
+    @classmethod
+    def app_store_server_notifications_vsees(cls, request, request_dict):
+        logger = logging.getLogger('apple_pay')
+        if request.method != 'POST':
+            logger.info(f'App Store服务器通知不是post请求, 参数{request_dict}')
+            return HttpResponse(status=400)
+        try:
+            request_data = json.loads(request.body)
+        except json.JSONDecodeError:
+            logger.error('无法解析请求体为JSON')
+            return HttpResponse(status=400)
+
+        request_data['bundleId'] = 'com.ansjer.zccloud'
+        updated_request_body = json.dumps(request_data)
+
+        if CONFIG_INFO == CONFIG_TEST:
+            logger.info('测试环境, App Store服务器通知发送到测试服')
+            response_test = requests.post(url="https://test.zositechc.cn/inAppPurchase/serverNotifications",
+                                          json=updated_request_body)
+            return HttpResponse(status=response_test.status_code)
+        response_us = requests.post(url="https://www.dvema.com/inAppPurchase/serverNotifications",
+                                    json=updated_request_body)
+        status_code = response_us.status_code
+        if status_code != 200:
+            response_eu = requests.post(url="https://api.zositeche.com/inAppPurchase/serverNotifications",
+                                        json=updated_request_body)
+            status_code = response_eu.status_code
+        if status_code == 200:
+            return HttpResponse(status=200)
+        return HttpResponse(status=400)
+
+    @classmethod
+    def vsees_notifications(cls, request):
+        logger = logging.getLogger('apple_pay')
+        logger.info('Vsees: App Store服务器通知请求类型:{}'.format(request.method))
+        logger.info('Vsees: App Store服务器通知参数:{}'.format(request.POST))
+        logger.info('Vsees: App Store服务器通知请求body:{}'.format(request.body))
         payload = json.loads(request.body.decode('utf-8'))
-        logger.info('App Store服务器通知payload:{}'.format(payload))
+        logger.info('Vsees: App Store服务器通知payload:{}'.format(payload))
         # 获取 signedPayload
         signed_payload = payload.get('signedPayload')
         if not signed_payload:
             return HttpResponse(status=400)
 
-        bundle_id = 'com.ansjer.zccloud'
-        environment = ENV
-        root_certificates = []
-        for cert_name in [
-            'AppleIncRootCertificate.cer', 'AppleComputerRootCertificate.cer',
-            'AppleRootCA-G2.cer', 'AppleRootCA-G3.cer'
-        ]:
-            cert_path = '{}/Ansjer/file/in_app_purchase/{}'.format(BASE_DIR, cert_name)
-            with open(cert_path, 'rb') as file:
-                # 读取文件内容
-                root_certificates.append(file.read())
-
-        enable_online_checks = True
-        app_apple_id = 1355964934  # 生产环境必需
-
-        # 验证签名并解码 payload
-        verifier = SignedDataVerifier(
-            root_certificates, enable_online_checks, environment, bundle_id, app_apple_id)
+        in_app_purchase = InAppPurchase(bundle_id="com.cloudlife.commissionf")
+
+        # SignedDataVerifier 用于解析查询到的交易信息
+        verifier = in_app_purchase.verifier
         decoded_payload = verifier.verify_and_decode_notification(signed_payload)
-        logger.info('App Store服务器通知decoded_payload: {}'.format(decoded_payload))
+
+        logger.info('Vsees: App Store服务器通知decoded_payload: {}'.format(decoded_payload))
+
         status_code = 200
+
         if str(decoded_payload.rawNotificationType) == "REFUND":
             # 一种通知类型,表示 App Store 成功退还了消耗性应用内购买、非消耗性应用内购买、自动续订或不可续订的交易。
             # revocationDate 包含退款交易的时间戳。originalTransactionId 和 productId 用于标识原始交易和产品。revocationReason 包含原因。
@@ -380,23 +839,25 @@ class InAppPurchaseView(View):
             decoded_transaction_information = verifier.verify_and_decode_signed_transaction(
                 decoded_payload.data.signedTransactionInfo)
             transaction_id = decoded_transaction_information.transactionId
-            logger.info('App Store服务器通知退款, transaction_id:{}'.format(transaction_id))
+            logger.info('Vsees: App Store服务器通知退款, transaction_id:{}'.format(transaction_id))
             orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
+
             # 2. 查找云存套餐使用表 和 云存套餐
             if orders_qs.exists():
-                orders_qs.update(status=5, updTime=int(time.time()))
+                orders_qs.update(status=11)
                 orderID = orders_qs[0].orderID
                 uid = orders_qs[0].UID
+                user_id = orders_qs[0].userID
+                # 3. 未使用则删除未使用套餐表,已使用过则删除设备正在使用套餐,并关闭设备云存
                 uid_bucket_qs = UID_Bucket.objects.filter(uid=uid, orderId=orderID, use_status=1,
                                                           endTime__gt=int(time.time()))
                 unused_uid_meal_qs = Unused_Uid_Meal.objects.filter(order_id=orderID)
-                ai_service_qs = AiService.objects.filter(uid=uid, orders=orderID, use_status=1,
+                ai_service_qs = AiService.objects.filter(uid=uid, orderId=orderID, use_status=1,
                                                          endTime__gt=int(time.time()))
                 if unused_uid_meal_qs.exists():
                     unused_uid_meal_qs.delete()
                 if uid_bucket_qs.exists():
-                    uid_bucket_qs.update(status=0, use_status=2, endTime=int(time.time()),
-                                         updateTime=int(time.time()))
+                    uid_bucket_qs.update(status=0, use_status=2, endTime=int(time.time()), updateTime=int(time.time()))
                 if ai_service_qs.exists():
                     ai_service_qs.update(detect_status=0, use_status=2, endTime=int(time.time()),
                                          updTime=int(time.time()))
@@ -405,54 +866,16 @@ class InAppPurchaseView(View):
                     thing_name = CommonService.query_serial_with_uid(uid)  # 存在序列号则为使用序列号作为物品名
                     topic_name = 'ansjer/generic/{}'.format(thing_name)
                     req_success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
-                    logger.info(f'App Store服务器通知用户退款, 关闭AI:{req_success}')
-                InAppRefund.objects.filter(transaction_id=transaction_id).update(updated_time=int(time.time()),
-                                                                                 refund_progress=2)
-
-            elif CONFIG_INFO == CONFIG_US:
-                url = "https://api.zositeche.com/inAppPurchase/AppStoreServerNotifications"
-                eur_response = requests.post(url=url, json=json.loads(request.body))
-                status_code = eur_response.status_code
+                    LOGGER.info(f'App Store服务器通知用户退款, 关闭AI:{req_success}')
 
-        elif str(decoded_payload.rawNotificationType) == "CONSUMPTION_REQUEST":
-            decoded_transaction_information = verifier.verify_and_decode_signed_transaction(
-                decoded_payload.data.signedTransactionInfo)
-            transaction_id = decoded_transaction_information.transactionId
-            app_account_token = decoded_transaction_information.appAccountToken
-            if app_account_token is None:
-                app_account_token = ""
-            orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
-            if orders_qs.exists():
-                orderID = orders_qs[0].orderID
-                uid = orders_qs[0].UID
-                app_type = orders_qs[0].app_type
-                now_time = int(time.time())
-                put_time = int(now_time + 11.5 * 60 * 60)
-                in_app_refund_qs = InAppRefund.objects.filter(transaction_id=transaction_id)
-                if in_app_refund_qs.exists():
-                    in_app_refund_qs.update(refund_progress=0, updated_time=now_time, app_account_token=app_account_token)
-                else:
-                    InAppRefund.objects.create(transaction_id=transaction_id, orderID=orderID,
-                                               uid=uid, app_type=app_type, created_time=now_time,
-                                               updated_time=now_time, put_time=put_time,
-                                               app_account_token=app_account_token)
-            elif CONFIG_INFO == CONFIG_US:
-                url = "https://api.zositeche.com/inAppPurchase/AppStoreServerNotifications"
-                eur_response = requests.post(url=url, json=json.loads(request.body))
-                status_code = eur_response.status_code
-
-        elif str(decoded_payload.rawNotificationType) == "REFUND_DECLINED":
-            decoded_transaction_information = verifier.verify_and_decode_signed_transaction(
-                decoded_payload.data.signedTransactionInfo)
-            transaction_id = decoded_transaction_information.transactionId
-            orders_qs = Order_Model.objects.filter(transaction_id=transaction_id)
-            if orders_qs.exists():
-                InAppRefund.objects.filter(transaction_id=transaction_id).update(refund_progress=3,
-                                                                                 updated_time=int(time.time()))
-            elif CONFIG_INFO == CONFIG_US:
-                url = "https://api.zositeche.com/inAppPurchase/AppStoreServerNotifications"
-                eur_response = requests.post(url=url, json=json.loads(request.body))
-                status_code = eur_response.status_code
+                # 4.发送邮件告知用户退款
+                email_content = f'{CONFIG_INFO}用户{user_id}, 订单:{orderID}, 设备{uid}退款'
+                S3Email().faEmail(email_content, 'servers@ansjer.com')
+            else:
+                if CONFIG_INFO == CONFIG_US:
+                    url = "https://api.zositeche.com/inAppPurchase/AppStoreServerNotifications"
+                    eur_response = requests.post(url=url, json=json.loads(request.body))
+                    status_code = eur_response.status_code
 
         return HttpResponse(status=status_code)
 

+ 44 - 1
Object/AppleInAppPurchaseSubscriptionObject.py

@@ -2,10 +2,14 @@
 # @File      : AppleInAppPurchaseSubscriptionObject.py
 # @Time      : 2024/9/4 11:58
 from appstoreserverlibrary.receipt_utility import ReceiptUtility
-from Ansjer.config import CONFIG_INFO, CONFIG_TEST, BASE_DIR, IN_APP_CONFIG
+
+from Ansjer.config import LOGGER, CONFIG_INFO, CONFIG_TEST, BASE_DIR, IN_APP_CONFIG
 from appstoreserverlibrary.api_client import AppStoreServerAPIClient
 from appstoreserverlibrary.models.Environment import Environment
 from appstoreserverlibrary.signed_data_verifier import SignedDataVerifier
+
+from Model.models import Order_Model, DeviceApplePackage
+
 ENV = Environment.SANDBOX if CONFIG_INFO == CONFIG_TEST else Environment.PRODUCTION
 
 
@@ -103,3 +107,42 @@ class InAppPurchase:
     def _initialize_receipt_util(self):
         receipt_util = ReceiptUtility()
         return receipt_util
+
+    def check_subscriptions(self, uid: str, subscription_group_id: str) -> bool:
+        try:
+            has_order = self._get_last_order(uid)
+            if not has_order:
+                return False
+
+            subscription_status = self._get_subscription_status(has_order, subscription_group_id)
+            return subscription_status
+
+        except Exception as e:
+            LOGGER.error(f"Error checking subscriptions: {str(e)}")
+            return False
+
+    def _get_last_order(self, uid: str) -> dict:
+        return Order_Model.objects.filter(UID=uid, payType=5).exclude(
+            original_transaction_id=""
+        ).values(
+            'transaction_id', 'original_transaction_id', 'orderID', 'addTime'
+        ).order_by('-addTime').first()
+
+    def _get_subscription_status(self, order: dict, subscription_group_id: str) -> bool:
+        device_apple_package = DeviceApplePackage.objects.filter(
+            original_transaction_id=order['original_transaction_id']
+        ).values("subscription_status").first()
+
+        if not device_apple_package or device_apple_package['subscription_status'] != 1:
+            return False
+
+        subscription_statuses = self.client.get_all_subscription_statuses(order['transaction_id'])
+        if not subscription_statuses.data:
+            return False
+
+        for subscription_status in subscription_statuses.data:
+            if str(subscription_status.subscriptionGroupIdentifier) == subscription_group_id:
+                if any(str(item.status) == "Status.ACTIVE" for item in subscription_status.lastTransactions):
+                    return True
+
+        return False