locky преди 8 месеца
родител
ревизия
c21edba409

+ 26 - 1
Controller/AppSetController.py

@@ -5,9 +5,11 @@ import time
 from django.db import transaction
 from django.views.generic.base import View
 
-from Ansjer.config import SERVER_TYPE
+from Ansjer.config import SERVER_TYPE, CONFIG_INFO, CONFIG_TEST
 from Model.models import AppSetModel, PromotionRuleModel, PopupsConfig, RedDotsConfig, Device_Info, UidSetModel, \
     UserOperationLog, Order_Model, IPAddr, RegionRestriction, UserSetStatus
+from Object.Enums.ConstantEnum import ConstantEnum
+from Object.Enums.RedisKeyConstant import RedisKeyConstant
 from Object.IPWeatherObject import IPQuery
 from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
@@ -53,6 +55,8 @@ class AppSetView(View):
             return self.status_by_ip(user_id, request, response)
         elif operation == 'userSetAdStatus':
             return self.user_set_ad_status(user_id, request_dict, response)
+        elif operation == 'promotionTime':
+            return self.promotion_time(user_id, response)
         else:
             return response.json(414)
 
@@ -368,3 +372,24 @@ class AppSetView(View):
         except Exception as e:
             LOGGER.info('设置用户广告状态异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
             return response.json(500)
+
+    @staticmethod
+    def promotion_time(user_id, response):
+        """
+        促销时间
+        @return:
+        """
+        redis_obj = RedisObject()
+        distribute_key = RedisKeyConstant.CLOUD_STORAGE_COUPONS.value + user_id
+        is_distributed = redis_obj.get_data(distribute_key)
+        if is_distributed == '1':
+            if CONFIG_INFO == CONFIG_TEST:
+                start_time = 1734080109
+            else:
+                start_time = ConstantEnum.PROMOTION_START_TIME.value
+            res = {
+                'start_time': start_time,
+                'end_time': ConstantEnum.PROMOTION_END_TIME.value
+            }
+            return response.json(0, res)
+        return response.json(0)

+ 53 - 21
Controller/CloudPhoto/CloudServiceController.py

@@ -6,11 +6,15 @@
 @Email   : zhangdongming@asj6.wecom.work
 @Software: PyCharm
 """
+import json
 import time
 
 from django.views import View
 
+from Ansjer.config import LOGGER
 from Model.models import CouponCombo, CouponModel
+from Object.Enums.RedisKeyConstant import RedisKeyConstant
+from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 
@@ -63,34 +67,62 @@ class CloudServiceController(View):
     def get_user_coupon_list(cls, user_id):
         """
         获取用户未使用优惠券配置ID列表
-        @param user_id:用户id
-        @return: coupon_qs
+        @param user_id: 用户id
+        @return: coupon_ids 列表,可能为空
+                  如果没有未使用的优惠券,返回空列表 []
         """
-        now_time = int(time.time())
-        coupon_qs = CouponModel.objects.filter(
-            userID=user_id,
-            use_status=0,
-            distribute_time__lte=now_time,
-            valid_time__gt=now_time
-        ).values('coupon_config__id')
-        return coupon_qs
+        try:
+            now_time = int(time.time())
+            coupon_conf_ids = CouponModel.objects.filter(
+                userID=user_id,
+                use_status=0,
+                distribute_time__lte=now_time,
+                valid_time__gt=now_time
+            ).values_list('coupon_config__id', flat=True)  # 使用 values_list 获取 ID 列表
+
+            return list(coupon_conf_ids)  # 可能为空
+        except Exception as e:
+            LOGGER.error('获取用户优惠券异常:userID:{}, error_line:{}, error_msg:{}'
+                         .format(user_id, e.__traceback__.tb_lineno, repr(e)))
+            return []
 
     @classmethod
     def get_combo_list(cls, coupon_type, coupon_id):
         """
         根据优惠券类型与优惠券ID,获取关联套餐列表
-        @param coupon_type: 优惠券类型
-        @param coupon_id: 套餐id
-        @return: coupon_list
+        :param coupon_type: 优惠券类型
+        :param coupon_id: 优惠券ID
+        :return: 关联的套餐ID列表
         """
-        combo_qs = CouponCombo.objects.filter(coupon_type=coupon_type, coupon_id=coupon_id) \
-            .values('combo_id')
-        combo_list = []
-        if not combo_qs.exists():
-            return combo_list
-        for item in combo_qs:
-            combo_list.append(item['combo_id'])
-        return combo_list
+        try:
+            redis_obj = RedisObject()  # 创建 Redis 对象以访问缓存
+            # 构建 Redis 缓存键
+            conf_key = f'{RedisKeyConstant.BASIC_CLOUD_COUPON.value}{coupon_type}:{coupon_id}'
+
+            # 尝试从 Redis 获取数据
+            conf_data = redis_obj.get_data(conf_key)
+            if conf_data:  # 如果缓存中存在数据,则直接返回
+                return json.loads(conf_data)
+
+                # 从数据库中查询关联的套餐ID
+            combo_qs = CouponCombo.objects.filter(coupon_type=coupon_type, coupon_id=coupon_id).values('combo_id')
+
+            # 初始化套餐ID列表
+            combo_list = []
+            if combo_qs.exists():  # 检查查询集是否存在数据
+                for item in combo_qs:
+                    combo_list.append(item['combo_id'])  # 逐个添加套餐ID
+
+            # 将查询结果存入 Redis 缓存
+            redis_obj.set_data(conf_key, json.dumps(combo_list), expire=RedisKeyConstant.EXPIRE_TIME_24_HOURS)
+
+            return combo_list  # 返回套餐ID列表
+
+        except Exception as e:
+            # 记录异常信息和相关上下文
+            LOGGER.error('获取优惠券套餐异常: couponID: {}, error_line: {}, error_msg: {}'
+                         .format(coupon_id, e.__traceback__.tb_lineno, repr(e)))
+            return []  # 返回空列表以表示失败
 
     @classmethod
     def get_coupon_list(cls, coupon_type, combo_id):

+ 12 - 10
Controller/CloudStorage.py

@@ -270,18 +270,21 @@ class CloudStorageView(View):
             store_list = list(store_qs)
             store_list.sort(key=itemgetter('bucket__area'))
             res = []
-            coupon_qs = '' if not user_id else CloudServiceController.get_user_coupon_list(user_id)
+            coupon_conf_ids = CloudServiceController.get_user_coupon_list(user_id)
+
             for area, items in groupby(store_list, key=itemgetter('bucket__area')):
                 items_list = list(items)
-                # 使用倒序遍历避免remove()操作导致索引错乱
                 for i in range(len(items_list) - 1, -1, -1):
                     item = items_list[i]
                     pay_type_qs = Pay_Type.objects.filter(store_meal=item['id']).values("id", "payment")
                     item['pay_type'] = list(pay_type_qs)
                     item['is_pay_cycle'] = 1 if item['cycle_config_id'] else 0
                     del item['cycle_config_id']
-                    item['isCoupon'] = False if not coupon_qs or not coupon_qs.exists() else \
-                        CloudStorageView.check_user_coupon_is_available(coupon_qs, item['id'])
+                    # 检查优惠券是否可用,并赋值给 item['isCoupon']
+                    if coupon_conf_ids:
+                        item['isCoupon'] = CloudStorageView.check_user_coupon_is_available(coupon_conf_ids, item['id'])
+                    else:
+                        item['isCoupon'] = False
                     for each in item['pay_type']:
                         if each['id'] == 10 and CONFIG_INFO != CONFIG_CN:
                             if is_ai == 0:
@@ -298,6 +301,7 @@ class CloudStorageView(View):
                             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)
             # 是否促销
@@ -333,20 +337,18 @@ class CloudStorageView(View):
             return response.json(500, 'error_line:{}, error_msg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
 
     @staticmethod
-    def check_user_coupon_is_available(coupon_qs, combo_id):
+    def check_user_coupon_is_available(coupon_conf_ids, combo_id):
         """
         查看用户优惠券是否可用
-        @param coupon_qs: 优惠券列表
+        @param coupon_conf_ids: 优惠券配置ids列表
         @param combo_id: 套餐id
         @return:
         """
-        if not coupon_qs.exists():
-            return False
         result = False
-        for item in coupon_qs:
+        for conf_id in coupon_conf_ids:
             if result:
                 break
-            combo_list = CloudServiceController.get_combo_list(0, item['coupon_config__id'])
+            combo_list = CloudServiceController.get_combo_list(0, conf_id)
             if not combo_list:
                 continue
             if combo_id in combo_list:

+ 41 - 0
Controller/CouponController.py

@@ -6,8 +6,10 @@ from django.db.models import F
 from django.http import HttpResponse
 from django.views.generic.base import View
 
+from Ansjer.config import LOGGER
 from Controller.CloudPhoto.CloudServiceController import CloudServiceController
 from Model.models import CouponModel, Device_User
+from Object.Enums.ConstantEnum import ConstantEnum
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
@@ -42,6 +44,9 @@ class CouponView(View):
             userID = tko.userID
             if operation == 'UserCoupon':  # 用户优惠券
                 return self.query_user_coupon(request_dict, userID, response)
+            elif operation == 'createCoupon':
+                self.generate_coupon_by_user(userID)
+                return response.json(0)
             else:
                 return response.json(414)
 
@@ -80,6 +85,8 @@ class CouponView(View):
     def query_user_coupon(self, request_dict, userID, response):  # 用户优惠券列表
         now_time = int(time.time())
         lang = request_dict.get('lang', 'en')
+        if lang not in ['en', 'cn']:
+            lang = 'en'
         coupon_obj = CouponModel.objects.filter(
             userID=userID,
             use_status=0,
@@ -116,3 +123,37 @@ class CouponView(View):
             'couponList': list(coupon_obj),
         }
         return response.json(0, result)
+
+    @staticmethod
+    def generate_coupon_by_user(user_id):
+        """
+        赠送优惠券圣诞节
+        @param user_id: 用户ID
+        @return: True | False
+        """
+        try:
+            end_timestamp = ConstantEnum.PROMOTION_END_TIME.value
+            now_time = int(time.time())
+            if now_time >= end_timestamp:
+                LOGGER.info('活动已结束,无法赠送优惠券')
+                return False
+
+                # 赠送三个优惠券
+            for i in range(1, 4):  # 赠送三个优惠券
+                coupon_config_id = 21 if i < 3 else 22  # 21 9折 22 8折
+                CouponModel.objects.create(
+                    use_status=0,
+                    distribute_time=now_time,
+                    valid_time=end_timestamp,
+                    userID=user_id,
+                    coupon_config_id=coupon_config_id,
+                    update_time=now_time,
+                    create_time=now_time
+                )
+
+            return True
+        except Exception as e:
+            # 记录异常信息
+            LOGGER.error('赠送优惠券异常 user: {}: errLine: {}, errMsg: {}'.format(
+                user_id, e.__traceback__.tb_lineno, repr(e)))
+            return False

+ 80 - 1
Controller/SysManage.py

@@ -12,6 +12,7 @@
 @Contact: chanjunkai@163.com
 """
 import os
+import threading
 import time
 
 from django.http import HttpResponse
@@ -19,9 +20,15 @@ from django.views.decorators.csrf import csrf_exempt
 from django.views.generic.base import View
 
 from Ansjer.config import BASE_DIR
-from Model.models import SysMsgModel, Device_Info, Ai_Push_Info
+from Controller.CouponController import CouponView
+from Model.models import SysMsgModel, Device_Info, Ai_Push_Info, UidSetModel, ExperienceContextModel, Order_Model, \
+    UID_Bucket
+from Object.Enums.ConstantEnum import ConstantEnum
+from Object.Enums.RedisKeyConstant import RedisKeyConstant
+from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
+from Service.CommonService import CommonService
 from Service.ModelService import ModelService
 
 
@@ -130,4 +137,76 @@ def initMsgFunc(request):
         'ai_count': ai_count,  # AI消息总数
         'uid_reset_count': uid_reset_count,  # 复位的设备数量
     }
+    # 如果没有发放过云存优惠券,异步发放
+    now_time = int(time.time())
+    start_time, end_time = ConstantEnum.PROMOTION_START_TIME.value, ConstantEnum.PROMOTION_END_TIME.value
+    # 缓存过期时间
+    expire = end_time - now_time
+    if expire > 0:
+        redis_obj = RedisObject()
+        distribute_key = RedisKeyConstant.CLOUD_STORAGE_COUPONS.value + userID
+        is_distributed = redis_obj.get_data(distribute_key)
+        if not is_distributed:
+            thread_kwargs = {
+                'user_id': userID,
+                'redis_obj': redis_obj,
+                'distribute_key': distribute_key,
+                'expire': expire,
+                'end_time': end_time
+            }
+            del_push_info_thread = threading.Thread(
+                target=distribute_cloud_storage_coupons,
+                kwargs=thread_kwargs)
+            del_push_info_thread.start()
     return response.json(0, res)
+
+
+def distribute_cloud_storage_coupons(user_id, redis_obj, distribute_key, expire, end_time):
+    """
+    发放云存优惠券
+    满足条件,用户存在以下三种类型的设备:
+    1. 未体验云存设备
+    2. 体验过未购买过
+    3. 购买过且已过期
+    @param user_id: 用户id
+    @param redis_obj: redis对象
+    @param distribute_key: 发放优惠券缓存key
+    @param expire: distribute_key过期时间
+    @param end_time: 活动结束时间
+    @return:
+    """
+    try:
+        generate_success = False
+        uid_list = Device_Info.objects.filter(userID_id=user_id).values_list('UID', flat=True)
+        if uid_list:
+            uid_set_qs = UidSetModel.objects.filter(uid__in=uid_list).values('uid', 'ucode', 'device_type')
+            if uid_set_qs.exists():
+                for uid_set in uid_set_qs:
+                    uid = uid_set['uid']
+                    # 判断设备是否支持云存
+                    is_cloud_vod = CommonService.is_cloud_device(uid_set['ucode'], uid_set['device_type'])
+                    if is_cloud_vod:
+                        # 未体验云存
+                        experience_qs = ExperienceContextModel.objects.filter(uid=uid, experience_type=0)
+                        if not experience_qs.exists():
+                            # 发放
+                            generate_success = CouponView.generate_coupon_by_user(user_id)
+                        else:
+                            # 体验过未购买过
+                            orders_qs = Order_Model.objects.filter(UID=uid, status=1, payType__in=[1, 4, 5])
+                            if not orders_qs.exists():
+                                # 发放
+                                generate_success = CouponView.generate_coupon_by_user(user_id)
+                            else:
+                                # 购买过且已过期
+                                # 没有未使用套餐,且过期时间在2024-12-29前
+                                vod_uid_bucket_qs = UID_Bucket.objects.filter(uid=uid, has_unused=0, endTime__lte=end_time)
+                                if vod_uid_bucket_qs.exists():
+                                    # 发放
+                                    generate_success = CouponView.generate_coupon_by_user(user_id)
+        if generate_success:
+            redis_obj.set_data(distribute_key, '1', expire)
+        else:
+            redis_obj.set_data(distribute_key, '0', expire)
+    except Exception as e:
+        return

+ 11 - 0
Object/Enums/ConstantEnum.py

@@ -0,0 +1,11 @@
+# @Author    : Rocky
+# @File      : ConstantEnum.py
+# @Time      : 2024/12/13 16:28
+from enum import IntEnum, unique
+
+
+@unique
+class ConstantEnum(IntEnum):
+    # 2024圣诞促销活动时间: 东部时间2024-12-23 00:00:00 - 2024-12-29 23:59:59
+    PROMOTION_START_TIME = 1734930000
+    PROMOTION_END_TIME = 1735534799

+ 10 - 0
Object/Enums/RedisKeyConstant.py

@@ -14,3 +14,13 @@ class RedisKeyConstant(Enum):
     ZOSI_DEVICE_VERSION_INFO = 'ZOSI:DEVICE:VERSION:'
     # 优惠券id锁
     COUPON_ID_LOCK = 'COUPON:ID:LOCK:'
+    # 云存优惠券
+    CLOUD_STORAGE_COUPONS = 'cloud_storage_coupons_'
+    # 基础模块用户优惠券
+    BASIC_CLOUD_COUPON = 'BASIC:CLOUD:COUPON:'
+
+    # Redis 过期时间常量(秒)
+    EXPIRE_TIME_60_SECONDS = 60  # 60秒
+    EXPIRE_TIME_30_MINUTES = 1800  # 30分钟
+    EXPIRE_TIME_1_HOUR = 3600  # 1小时
+    EXPIRE_TIME_24_HOURS = 86400  # 24小时