Selaa lähdekoodia

Merge branch 'test' of http://192.168.136.99:3000/servers/ASJServer into peng

 Conflicts:
	Controller/AiController.py
	Controller/CloudStorage.py
	Controller/EquipmentManagerV2.py
	Controller/EquipmentManagerV3.py
	Controller/OrderContrller.py
peng 3 vuotta sitten
vanhempi
commit
13a2bc65bd

+ 23 - 25
AdminController/ServeManagementController.py

@@ -538,31 +538,29 @@ class serveManagement(View):
         cdk_list = []
         sm_qs = Store_Meal.objects.filter(
             pay_type__payment='cdk_pay', bucket__mold=mold, is_show=0)
-        if sm_qs.exists:
-            rank = sm_qs[0].id
-            for i in range(int(cdk_num)):
-                nowTime = int(time.time())
-                cdk = hashlib.md5((str(uuid.uuid1()) +
-                                   str(nowTime)).encode('utf-8')).hexdigest()
-                cdk_model = CDKcontextModel(
-                    cdk=cdk,
-                    create_time=nowTime,
-                    valid_time=0,
-                    is_activate=0,
-                    is_down=0,
-                    rank_id=rank,
-                    order=order,
-                )
-                cdk_list.append(cdk_model)
-            try:
-                CDKcontextModel.objects.bulk_create(cdk_list)
-            except Exception as e:
-                print(repr(e))
-                return response.json(404, repr(e))
-            else:
-                return response.json(0)
-
-        return response.json(0)
+        if not sm_qs.exists():
+            return response.json(173)
+        rank = sm_qs[0].id
+        for i in range(int(cdk_num)):
+            nowTime = int(time.time())
+            cdk = hashlib.md5((str(uuid.uuid1()) +
+                               str(nowTime)).encode('utf-8')).hexdigest()
+            cdk_model = CDKcontextModel(
+                cdk=cdk,
+                create_time=nowTime,
+                valid_time=0,
+                is_activate=0,
+                is_down=0,
+                rank_id=rank,
+                order=order,
+            )
+            cdk_list.append(cdk_model)
+        try:
+            CDKcontextModel.objects.bulk_create(cdk_list)
+        except Exception as e:
+            return response.json(404, repr(e))
+        else:
+            return response.json(0)
 
     def deleteCdk(self, request_dict, response):
         cdk_id = request_dict.get("id", None)

+ 235 - 0
AdminController/UnicomManageController.py

@@ -0,0 +1,235 @@
+# Copyright (C) 2022 #
+# @Time    : 2022/7/18 16:16
+# @Author  : ghl
+# @Email   : Guanhailogn@asj6.wecom.work
+# @File    : UnicomManageController.py
+# @Software: PyCharm
+
+from django.db import transaction
+from django.views import View
+
+from Model.models import UnicomComboOrderInfo, UnicomCombo, UnicomDeviceInfo, Pay_Type
+from Object.ResponseObject import ResponseObject
+
+
+class UnicomComboView(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()
+        print(request)
+        # 编辑套餐信息
+        if operation == 'get/info':
+            return self.get_unicom_info(request_dict, response)
+        # 获取套餐表
+        elif operation == 'get/pay':
+            return self.get_pay_type(request_dict, response)
+        # 编辑卡套餐
+        elif operation == 'edit/combo':
+            return self.edit_combo(request_dict, response)
+        # 新增套餐
+        elif operation == 'add/combo':
+            return self.add_combo(response, request_dict)
+        # 获取设备套餐信息
+        elif operation == 'order/info':
+            return self.get_order_info(response, request_dict)
+        # 获取用户信息
+        elif operation == 'user/info':
+            return self.get_user_info(response, request_dict)
+
+    @staticmethod
+    def get_user_info(response, request_dict):
+        pass
+
+    @staticmethod
+    def get_order_info(response, request_dict):
+        serial_no = request_dict.get('serialNo', None)
+        if not all([serial_no]):
+            return response.json(444)
+        get_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no).values('iccid')
+        iccid = get_info_qs[0]['iccid']
+        combo_info_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid).values()
+        if not combo_info_qs.exists():
+            return response.json(173)
+        try:
+            combo_list = []
+            for combo_info in combo_info_qs:
+                combo_list.append(combo_info)
+            return response.json(0, combo_list)
+        except Exception as e:
+            return response.json(500, e)
+
+    @classmethod
+    def edit_combo(cls, request_dict, response):
+        """
+
+        """
+        combo_id = request_dict.get('comboID', None)
+        package_id = request_dict.get('packageId', None)
+        combo_name = request_dict.get('comboName', None)
+        status = request_dict.get('status', None)
+        combo_type = request_dict.get('comboType', None)
+        flow_total = request_dict.get('flowTotal', None)
+        expiration_days = request_dict.get('expirationDays', None)
+        expiration_type = request_dict.get('expirationType', None)
+        pay_type = request_dict.get('payType', None)
+        price = request_dict.get('price', None)
+        remark = request_dict.get('remark', None)
+        updated_time = request_dict.get('updatedTime', None)
+        created_time = request_dict.get('createdTime', None)
+        is_show = request_dict.get('show', None)
+
+        if not all([combo_id]):
+            return response.json(444)
+        UnicomCombo.objects.filter(id=combo_id).values()
+
+        try:
+            with transaction.atomic():
+                re_data = {
+                    'package_id': package_id,
+                    'combo_name': combo_name,
+                    'status': status,
+                    'combo_type': combo_type,
+                    'flow_total': flow_total,
+                    'expiration_days': expiration_days,
+                    'expiration_type': expiration_type,
+                    'price': price,
+                    'remark': remark,
+                    'updated_time': updated_time,
+                    'created_time': created_time,
+                    'is_show': is_show
+                }
+                UnicomCombo.objects.filter(id=combo_id).update(**re_data)
+                UnicomCombo.objects.get(id=combo_id).pay_type.set(pay_type)
+                # UnicomCombo.objects.create(**re_data).pay_type.set(pay_type)
+                return response.json(0)
+
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def add_combo(response, request_dict):
+        """
+        新增卡套餐
+        """
+        combo_id = request_dict.get('ID', None)
+        package_id = request_dict.get('packageId', None)
+        combo_name = request_dict.get('comboName', None)
+        status = request_dict.get('status', None)
+        combo_type = request_dict.get('comboType', None)
+        flow_total = request_dict.get('flowTotal', None)
+        expiration_days = request_dict.get('expirationDays', None)
+        expiration_type = request_dict.get('expirationDays', None)
+        pay_type = request_dict.get('payType', None)
+        price = request_dict.get('price', None)
+        remark = request_dict.get('remark', None)
+        updated_time = request_dict.get('updatedTime', None)
+        created_time = request_dict.get('createdTime', None)
+        is_show = request_dict.get('show', None)
+        pageNo = request_dict.get('pageNO', None)
+        pageSize = request_dict.get('pageSize', None)
+
+        if not all([pageNo, pageSize]):
+            return response.json(444)
+        try:
+            with transaction.atomic():
+                re_data = {
+                    'package_id': package_id,
+                    'combo_name': combo_name,
+                    'status': status,
+                    'combo_type': combo_type,
+                    'flow_total': flow_total,
+                    'expiration_days': expiration_days,
+                    'expiration_type': expiration_type,
+                    'price': price,
+                    'remark': remark,
+                    'updated_time': updated_time,
+                    'created_time': created_time,
+                    'is_show': is_show
+                }
+                UnicomCombo.objects.filter(id=combo_id).update(**re_data)
+                UnicomCombo.objects.get(id=combo_id).pay_type.set(pay_type)
+                UnicomCombo.objects.create(**re_data).pay_type.set(pay_type)
+                return response.json(0)
+
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_unicom_info(request_dict, response):
+        """
+        获取套餐详细表
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        pageNo = request_dict.get('pageNo', None)
+        pageSize = request_dict.get('pageSize', None)
+        if not all([pageNo, pageSize]):
+            return response.json(444)
+        page = int(pageNo)
+        line = int(pageSize)
+        try:
+            combo_qs = UnicomCombo.objects.filter(is_del=False) \
+                           .order_by('sort').values('id', 'combo_name',
+                                                    'flow_total',
+                                                    'expiration_days',
+                                                    'expiration_type', 'price',
+                                                    'remark')[(page - 1) * line:page * line]
+            if not combo_qs.exists():
+                return response.json(0, [])
+            total = combo_qs.count()
+            combo_list = []
+            for item in combo_qs:
+                # 获取支付方式列表
+                pay_type_qs = Pay_Type.objects.filter(unicomcombo=item['id']).values('id', 'payment')
+                combo_list.append({
+                    'id': item['id'],
+                    'comboName': item['combo_name'],
+                    'flowTotal': item['flow_total'],
+                    'expirationDays': item['expiration_days'],
+                    'expirationType': item['expiration_type'],
+                    'price': item['price'],
+                    'remark': item['remark'],
+                    'payTypes': list(pay_type_qs),
+                })
+            return response.json(0, {'list': combo_list, 'total': total})
+        except Exception as e:
+            return response.json(177, repr(e))
+
+    @classmethod
+    def get_pay_type(cls, request_dict, response):
+        """
+        获取套餐表
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        combo_id = request_dict.get('comboID', None)
+
+        if not all([combo_id]):
+            return response.json(444)
+
+        combo_id_qs = UnicomCombo.objects.filter(id=combo_id).values('pay_type')
+        if combo_id_qs.exists():
+            pass
+        pay_type_qs = Pay_Type.objects.all().values('id', 'payment')
+        if not pay_type_qs.exists():
+            return response.json(444)
+        try:
+            pay_type_list = []
+            for pay_type in pay_type_qs:
+                pay_type_qs.exists()
+                pay_type_list.append(pay_type)
+            return response.json(0, pay_type_list)
+        except Exception as e:
+            return response.json(500, e)

+ 2 - 1
Ansjer/server_urls/loocam_url.py

@@ -9,7 +9,7 @@
 from django.urls import re_path
 
 from Controller.SensorGateway import GatewayFamilyRoomController, SubDeviceController, GatewayFamilyMemberController, \
-    EquipmentFamilyController, GatewayDeviceController
+    EquipmentFamilyController, GatewayDeviceController, SmartSceneController
 
 urlpatterns = [
     re_path(r'^sensor/gateway/(?P<operation>.*)$', EquipmentFamilyController.EquipmentFamilyView.as_view()),
@@ -18,4 +18,5 @@ urlpatterns = [
             GatewayFamilyMemberController.GatewayFamilyMemberView.as_view()),
     re_path(r'^gateway/subdevice/(?P<operation>.*)$', SubDeviceController.GatewaySubDeviceView.as_view()),
     re_path(r'^gateway/device/info/(?P<operation>.*)$', GatewayDeviceController.GatewayDeviceView.as_view()),
+    re_path(r'^smartscene/(?P<operation>.*)$', SmartSceneController.SmartSceneView.as_view()),
 ]

+ 5 - 1
Ansjer/server_urls/unicom_url.py

@@ -8,8 +8,12 @@
 """
 from django.urls import re_path
 
-from Controller.UnicomCombo import UnicomComboController
+from Controller.UnicomCombo import UnicomComboController, UnicomComboPayNotifyController, UnicomComboTaskController
+from AdminController import UnicomManageController
 
 urlpatterns = [
     re_path(r'^api/(?P<operation>.*)$', UnicomComboController.UnicomComboView.as_view()),
+    re_path(r'^wap/pay/(?P<operation>.*)$', UnicomComboPayNotifyController.UnicomComboPayNotifyView.as_view()),
+    re_path(r'^combo/cron/(?P<operation>.*)$', UnicomComboTaskController.UnicomComboTaskView.as_view()),
+    re_path(r'^manage/(?P<operation>.*)$',UnicomManageController.UnicomComboView.as_view()),
 ]

+ 1 - 0
Ansjer/urls.py

@@ -410,3 +410,4 @@ urlpatterns = [
     re_path('(?P<path>.*)', LogManager.errorPath),
 
 ]
+# 鹏提交测试代码

+ 2 - 2
Controller/AiController.py

@@ -369,8 +369,8 @@ class AiView(View):
             device_info_qs = Device_Info.objects.filter(UID=uid).values('serial_number', 'Type')
             serial_number = device_info_qs[0]['serial_number']
             device_type = device_info_qs[0]['Type']
-            if serial_number and device_type == 101:
-                ai_service_data['uid'] = CommonService.get_full_serial_number(uid, serial_number, device_type)
+            if serial_number:
+                ai_service_data['serial_number'] = CommonService.get_full_serial_number(uid, serial_number, device_type)
 
             ai_service_data['endTime'] = sum_end_time
             return response.json(0, [ai_service_data])

+ 6 - 6
Controller/CloudStorage.py

@@ -743,7 +743,7 @@ class CloudStorageView(View):
                     device_info_qs = Device_Info.objects.filter(UID=UID).values('serial_number', 'Type')
                     serial_number = device_info_qs[0]['serial_number']
                     device_type = device_info_qs[0]['Type']
-                    if serial_number and device_type == 101:
+                    if serial_number:
                         device_name = CommonService.get_full_serial_number(UID, serial_number, device_type)
                     else:
                         device_name = UID
@@ -898,7 +898,7 @@ class CloudStorageView(View):
                 device_info_qs = Device_Info.objects.filter(UID=UID).values('serial_number', 'Type')
                 serial_number = device_info_qs[0]['serial_number']
                 device_type = device_info_qs[0]['Type']
-                if serial_number and device_type == 101:
+                if serial_number:
                     device_name = CommonService.get_full_serial_number(UID, serial_number, device_type)
                 else:
                     device_name = UID
@@ -1033,7 +1033,7 @@ class CloudStorageView(View):
                     device_info_qs = Device_Info.objects.filter(UID=UID).values('serial_number', 'Type')
                     serial_number = device_info_qs[0]['serial_number']
                     device_type = device_info_qs[0]['Type']
-                    if serial_number and device_type == 101:
+                    if serial_number:
                         device_name = CommonService.get_full_serial_number(UID, serial_number, device_type)
                     else:
                         device_name = UID
@@ -1387,7 +1387,7 @@ class CloudStorageView(View):
                 device_info_qs = Device_Info.objects.filter(UID=uid).values('serial_number', 'Type')
                 serial_number = device_info_qs[0]['serial_number']
                 device_type = device_info_qs[0]['Type']
-                if serial_number and device_type == 101:
+                if serial_number:
                     device_name = CommonService.get_full_serial_number(uid, serial_number, device_type)
                 else:
                     device_name = uid
@@ -1489,7 +1489,7 @@ class CloudStorageView(View):
         device_id = uid
         serial_number = dv_qs[0]['serial_number']
         device_type = dv_qs[0]['Type']
-        if serial_number and device_type == 101:
+        if serial_number:
             device_id = CommonService.get_full_serial_number(uid, serial_number, device_type)
 
         uid_bucket[0]['uid'] = device_id
@@ -1638,7 +1638,7 @@ class CloudStorageView(View):
                     device_info_qs = Device_Info.objects.filter(UID=uid).values('serial_number', 'Type')
                     serial_number = device_info_qs[0]['serial_number']
                     device_type = device_info_qs[0]['Type']
-                    if serial_number and device_type == 101:
+                    if serial_number:
                         device_name = CommonService.get_full_serial_number(uid, serial_number, device_type)
                     else:
                         device_name = uid

+ 78 - 75
Controller/DetectController.py

@@ -88,83 +88,86 @@ class DetectControllerView(View):
         #     qs = qs.filter(eventTime__range=(startTime, endTime))
         # if eventType:
         #     qs = qs.filter(eventType=eventType)
-        if startTime and endTime:
-            qs, count = EquipmentInfoService.find_by_start_time_equipment_info(page, line, userID, startTime,
-                                                                               endTime, eventType,
-                                                                               request_dict.get('uids', None))
+        try:
+            if startTime and endTime:
+                qs, count = EquipmentInfoService.find_by_start_time_equipment_info(page, line, userID, startTime,
+                                                                                   endTime, eventType,
+                                                                                   request_dict.get('uids', None))
 
-        else:
-            # 默认查询近七天消息推送
-            qs, count = EquipmentInfoService.get_equipment_info_week_all(page, line, userID, startTime, endTime,
-                                                                         eventType,
-                                                                         request_dict.get('uids', None))
-        logger.info('<<<|||分表查询结果count:{}'.format(count))
-        uids = request_dict.get('uids', None)
-        if uids:
-            uid_list = uids.split(',')
-            # qs = qs.filter(devUid__in=uid_list)
-            dvqs = Device_Info.objects.filter(UID__in=uid_list, userID_id=userID).values('UID', 'Type', 'NickName')
-            uid_type_dict = {}
-            for dv in dvqs:
-                uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
-        else:
-            dvqs = Device_Info.objects.filter(userID_id=userID).values('UID', 'Type', 'NickName')
-            uid_type_dict = {}
-            for dv in dvqs:
-                uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
-        # print(uid_type_dict)
-        if not qs or count == 0 or not qs.exists():
-            return response.json(0, {'datas': [], 'count': 0})
-        # if not qs.exists():
-        #     return response.json(0, {'datas': [], 'count': 0})
-        # qs = qs.values('id', 'devUid', 'devNickName', 'Channel', 'eventType', 'status', 'alarm', 'eventTime',
-        #                'receiveTime', 'is_st', 'addTime')
-
-        # count = qs.count()
-        # qr = qs[(page - 1) * line:page * line]
-        qr = qs
-        res = []
-        auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
-        img_bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'apg')
-        # vod_time_list = []
-        for p in qr:
-            devUid = p['devUid']
-            eventTime = p['eventTime']
-            channel = p['Channel']
-            if p['is_st'] == 1:
-                p['img'] = img_bucket.sign_url('GET', '{uid}/{channel}/{time}.jpeg'.
-                                               format(uid=devUid, channel=p['Channel'], time=eventTime), 300)
-                p['img_list'] = [img_bucket.sign_url('GET', '{uid}/{channel}/{time}.jpeg'.
-                                                     format(uid=devUid, channel=channel, time=eventTime), 300)]
-            elif p['is_st'] == 2:
-                # 列表装载回放时间戳标记
-                vodqs = VodHlsModel.objects.filter(uid=devUid, channel=channel, time=int(eventTime)) \
-                    .values("bucket__bucket", "bucket__endpoint")
-                # print(vodqs)
-                if vodqs.exists():
-                    bucket_name = vodqs[0]['bucket__bucket']
-                    endpoint = vodqs[0]['bucket__endpoint']
-                    bucket = oss2.Bucket(auth, endpoint, bucket_name)
-                    ts = '{uid}/vod{channel}/{etime}/ts0.ts'.format(uid=devUid, channel=p['Channel'], etime=eventTime)
-                    thumb0 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_0000,w_700'})
-                    thumb1 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_1000,w_700'})
-                    thumb2 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_2000,w_700'})
-                    # thumb3 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_3000,w_700'})
-                    p['img_list'] = [thumb0, thumb1, thumb2]
-            elif p['is_st'] == 3:
-                # 列表装载回放时间戳标记
-                p['img_list'] = []
-                for i in range(p['is_st']):
-                    img = img_bucket.sign_url('GET', '{uid}/{channel}/{time}_{st}.jpeg'.
-                                              format(uid=devUid, channel=p['Channel'], time=eventTime, st=i), 300)
-                    p['img_list'].append(img)
-            if devUid in uid_type_dict.keys():
-                p['uid_type'] = uid_type_dict[devUid]['type']
-                p['devNickName'] = uid_type_dict[devUid]['NickName']
             else:
-                p['uid_type'] = ''
-            res.append(p)
-        return response.json(0, {'datas': res, 'count': count})
+                # 默认查询近七天消息推送
+                qs, count = EquipmentInfoService.get_equipment_info_week_all(page, line, userID, startTime, endTime,
+                                                                             eventType,
+                                                                             request_dict.get('uids', None))
+            logger.info('<<<|||分表查询结果count:{}'.format(count))
+            uids = request_dict.get('uids', None)
+            if uids:
+                uid_list = uids.split(',')
+                # qs = qs.filter(devUid__in=uid_list)
+                dvqs = Device_Info.objects.filter(UID__in=uid_list, userID_id=userID).values('UID', 'Type', 'NickName')
+                uid_type_dict = {}
+                for dv in dvqs:
+                    uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
+            else:
+                dvqs = Device_Info.objects.filter(userID_id=userID).values('UID', 'Type', 'NickName')
+                uid_type_dict = {}
+                for dv in dvqs:
+                    uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
+            # print(uid_type_dict)
+            if not qs or count == 0 or not qs.exists():
+                return response.json(0, {'datas': [], 'count': 0})
+            # if not qs.exists():
+            #     return response.json(0, {'datas': [], 'count': 0})
+            # qs = qs.values('id', 'devUid', 'devNickName', 'Channel', 'eventType', 'status', 'alarm', 'eventTime',
+            #                'receiveTime', 'is_st', 'addTime')
+
+            # count = qs.count()
+            # qr = qs[(page - 1) * line:page * line]
+            qr = qs
+            res = []
+            auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
+            img_bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'apg')
+            # vod_time_list = []
+            for p in qr:
+                devUid = p['devUid']
+                eventTime = p['eventTime']
+                channel = p['Channel']
+                if p['is_st'] == 1:
+                    p['img'] = img_bucket.sign_url('GET', '{uid}/{channel}/{time}.jpeg'.
+                                                   format(uid=devUid, channel=p['Channel'], time=eventTime), 300)
+                    p['img_list'] = [img_bucket.sign_url('GET', '{uid}/{channel}/{time}.jpeg'.
+                                                         format(uid=devUid, channel=channel, time=eventTime), 300)]
+                elif p['is_st'] == 2:
+                    # 列表装载回放时间戳标记
+                    vodqs = VodHlsModel.objects.filter(uid=devUid, channel=channel, time=int(eventTime)) \
+                        .values("bucket__bucket", "bucket__endpoint")
+                    # print(vodqs)
+                    if vodqs.exists():
+                        bucket_name = vodqs[0]['bucket__bucket']
+                        endpoint = vodqs[0]['bucket__endpoint']
+                        bucket = oss2.Bucket(auth, endpoint, bucket_name)
+                        ts = '{uid}/vod{channel}/{etime}/ts0.ts'.format(uid=devUid, channel=p['Channel'], etime=eventTime)
+                        thumb0 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_0000,w_700'})
+                        thumb1 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_1000,w_700'})
+                        thumb2 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_2000,w_700'})
+                        # thumb3 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_3000,w_700'})
+                        p['img_list'] = [thumb0, thumb1, thumb2]
+                elif p['is_st'] == 3:
+                    # 列表装载回放时间戳标记
+                    p['img_list'] = []
+                    for i in range(p['is_st']):
+                        img = img_bucket.sign_url('GET', '{uid}/{channel}/{time}_{st}.jpeg'.
+                                                  format(uid=devUid, channel=p['Channel'], time=eventTime, st=i), 300)
+                        p['img_list'].append(img)
+                if devUid in uid_type_dict.keys():
+                    p['uid_type'] = uid_type_dict[devUid]['type']
+                    p['devNickName'] = uid_type_dict[devUid]['NickName']
+                else:
+                    p['uid_type'] = ''
+                res.append(p)
+            return response.json(0, {'datas': res, 'count': count})
+        except Exception as e:
+            return response.json(474)
 
     def do_change_status(self, userID, request_dict, response):
         token_val = request_dict.get('token_val', None)

+ 144 - 141
Controller/DetectControllerV2.py

@@ -300,156 +300,159 @@ class DetectControllerViewV2(View):
 
         # qs = Equipment_Info.objects.filter(userID_id=userID).order_by('-eventTime')
         # qs = qs.filter(eventTime__gt=now_time - 3600 * 168)
-        # 根据时间筛选消息推送
-        if startTime and endTime:
-            qs, count = EquipmentInfoService.find_by_start_time_equipment_info(page, line, userID, startTime,
-                                                                               endTime, eventType,
-                                                                               request_dict.get('uids', None))
+        try:
+            # 根据时间筛选消息推送
+            if startTime and endTime:
+                qs, count = EquipmentInfoService.find_by_start_time_equipment_info(page, line, userID, startTime,
+                                                                                   endTime, eventType,
+                                                                                   request_dict.get('uids', None))
 
-        else:
-            # 默认查询近七天消息推送
-            qs, count = EquipmentInfoService.get_equipment_info_week_all(page, line, userID, startTime, endTime,
-                                                                         eventType,
-                                                                         request_dict.get('uids', None))
-        # if startTime and endTime:
-        #     qs = qs.filter(eventTime__range=(startTime, endTime))
-        # if eventType:
-        #     if ',' in eventType:  # 兼容AI查询
-        #         eventTypeList = eventType.split(',')
-        #         eventTypeList = [int(i.strip()) for i in eventTypeList]
-        #         qs = qs.filter(eventType__in=eventTypeList)
-        #     else:
-        #         qs = qs.filter(eventType=eventType)
-        uids = request_dict.get('uids', None)
-        if uids:
-            uid_list = uids.split(',')
-            # qs = qs.filter(devUid__in=uid_list)
-            dvqs = Device_Info.objects.filter(UID__in=uid_list, userID_id=userID).values('UID', 'Type', 'NickName')
-            uid_type_dict = {}
-            for dv in dvqs:
-                uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
-        else:
-            dvqs = Device_Info.objects.filter(userID_id=userID).values('UID', 'Type', 'NickName')
-            uid_type_dict = {}
-            for dv in dvqs:
-                uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
-        # print(uid_type_dict)
-        if not qs or count == 0 or not qs.exists():
-            return response.json(0, {'datas': [], 'count': 0})
-        # qs = qs.values('id', 'devUid', 'devNickName', 'Channel', 'eventType', 'status', 'alarm', 'eventTime',
-        #                'receiveTime', 'is_st', 'addTime', 'storage_location', 'borderCoords')
-
-        # count = qs.count()
-        # qr = qs[(page - 1) * line:page * line]
-        qr = qs
-        res = []
-        auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
-        oss_img_bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'apg')
-        aws_s3_guonei = boto3.client(
-            's3',
-            aws_access_key_id=AWS_ACCESS_KEY_ID[0],
-            aws_secret_access_key=AWS_SECRET_ACCESS_KEY[0],
-            config=botocore.client.Config(signature_version='s3v4'),
-            region_name='cn-northwest-1'
-        )
-        aws_s3_guowai = boto3.client(
-            's3',
-            aws_access_key_id=AWS_ACCESS_KEY_ID[1],
-            aws_secret_access_key=AWS_SECRET_ACCESS_KEY[1],
-            config=botocore.client.Config(signature_version='s3v4'),
-            region_name='us-east-1'
-        )
-        # vod_time_list = []
-        # ai消息标识所有组合标签
-        ai_all_event_type = EquipmentInfoService.get_all_comb_event_type()
-        for p in qr:
-            devUid = p['devUid']
-            eventTime = p['eventTime']
-            channel = p['Channel']
-            storage_location = p['storage_location']
-            if p['is_st'] == 1:
-                thumbspng = '{uid}/{channel}/{time}.jpeg'.format(uid=devUid, channel=p['Channel'], time=eventTime)
-                if storage_location == 1:  # oss
-                    response_url = oss_img_bucket.sign_url('GET', thumbspng, 300)
-                    p['img'] = response_url
-                    p['img_list'] = [response_url]
-                elif region == 2 and storage_location == 2:  # 2:国内,aws
-                    response_url = aws_s3_guonei.generate_presigned_url('get_object',
-                                                                        Params={'Bucket': 'push', 'Key': thumbspng},
-                                                                        ExpiresIn=300)
-                    p['img'] = response_url
-                    p['img_list'] = [response_url]
-                elif region == 1 and storage_location == 2:  # 1:国外,aws
-                    response_url = aws_s3_guowai.generate_presigned_url('get_object',
-                                                                        Params={'Bucket': 'foreignpush',
-                                                                                'Key': thumbspng},
-                                                                        ExpiresIn=300)
-                    p['img'] = response_url
-                    p['img_list'] = [response_url]
-
-            elif p['is_st'] == 2:
-                # 列表装载回放时间戳标记
-                vodqs = VodHlsModel.objects.filter(uid=devUid, channel=channel, time=int(eventTime)) \
-                    .values("bucket__bucket", "bucket__endpoint")
-                # print(vodqs)
-                if vodqs.exists():
-                    bucket_name = vodqs[0]['bucket__bucket']
-                    endpoint = vodqs[0]['bucket__endpoint']
-                    bucket = oss2.Bucket(auth, endpoint, bucket_name)
-                    ts = '{uid}/vod{channel}/{etime}/ts0.ts'.format(uid=devUid, channel=p['Channel'], etime=eventTime)
-                    if storage_location == 1:  # oss
-                        thumb0 = bucket.sign_url('GET', ts, 3600,
-                                                 params={'x-oss-process': 'video/snapshot,t_0000,w_700'})
-                        thumb1 = bucket.sign_url('GET', ts, 3600,
-                                                 params={'x-oss-process': 'video/snapshot,t_1000,w_700'})
-                        thumb2 = bucket.sign_url('GET', ts, 3600,
-                                                 params={'x-oss-process': 'video/snapshot,t_2000,w_700'})
-                        # thumb3 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_3000,w_700'})
-                        p['img_list'] = [thumb0, thumb1, thumb2]
-                    elif region == 2 and storage_location == 2:  # 2:国内,aws
-                        thumb = aws_s3_guonei.generate_presigned_url('get_object',
-                                                                     Params={'Bucket': 'push', 'Key': ts},
-                                                                     ExpiresIn=3600)
-                        p['img_list'] = [thumb]
-                    elif region == 1 and storage_location == 2:  # 1:国外,aws
-                        thumb = aws_s3_guowai.generate_presigned_url('get_object',
-                                                                     Params={'Bucket': 'foreignpush', 'Key': ts},
-                                                                     ExpiresIn=3600)
-                        p['img_list'] = [thumb]
-            elif p['is_st'] == 3 or p['is_st'] == 4:
-                # 列表装载回放时间戳标记
-                p['img_list'] = []
-                for i in range(p['is_st']):
-                    thumbspng = '{uid}/{channel}/{time}_{st}.jpeg'.format(uid=devUid, channel=p['Channel'],
-                                                                          time=eventTime, st=i)
+            else:
+                # 默认查询近七天消息推送
+                qs, count = EquipmentInfoService.get_equipment_info_week_all(page, line, userID, startTime, endTime,
+                                                                             eventType,
+                                                                             request_dict.get('uids', None))
+            # if startTime and endTime:
+            #     qs = qs.filter(eventTime__range=(startTime, endTime))
+            # if eventType:
+            #     if ',' in eventType:  # 兼容AI查询
+            #         eventTypeList = eventType.split(',')
+            #         eventTypeList = [int(i.strip()) for i in eventTypeList]
+            #         qs = qs.filter(eventType__in=eventTypeList)
+            #     else:
+            #         qs = qs.filter(eventType=eventType)
+            uids = request_dict.get('uids', None)
+            if uids:
+                uid_list = uids.split(',')
+                # qs = qs.filter(devUid__in=uid_list)
+                dvqs = Device_Info.objects.filter(UID__in=uid_list, userID_id=userID).values('UID', 'Type', 'NickName')
+                uid_type_dict = {}
+                for dv in dvqs:
+                    uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
+            else:
+                dvqs = Device_Info.objects.filter(userID_id=userID).values('UID', 'Type', 'NickName')
+                uid_type_dict = {}
+                for dv in dvqs:
+                    uid_type_dict[dv['UID']] = {'type': dv['Type'], 'NickName': dv['NickName']}
+            # print(uid_type_dict)
+            if not qs or count == 0 or not qs.exists():
+                return response.json(0, {'datas': [], 'count': 0})
+            # qs = qs.values('id', 'devUid', 'devNickName', 'Channel', 'eventType', 'status', 'alarm', 'eventTime',
+            #                'receiveTime', 'is_st', 'addTime', 'storage_location', 'borderCoords')
+
+            # count = qs.count()
+            # qr = qs[(page - 1) * line:page * line]
+            qr = qs
+            res = []
+            auth = oss2.Auth(OSS_STS_ACCESS_KEY, OSS_STS_ACCESS_SECRET)
+            oss_img_bucket = oss2.Bucket(auth, 'oss-cn-shenzhen.aliyuncs.com', 'apg')
+            aws_s3_guonei = boto3.client(
+                's3',
+                aws_access_key_id=AWS_ACCESS_KEY_ID[0],
+                aws_secret_access_key=AWS_SECRET_ACCESS_KEY[0],
+                config=botocore.client.Config(signature_version='s3v4'),
+                region_name='cn-northwest-1'
+            )
+            aws_s3_guowai = boto3.client(
+                's3',
+                aws_access_key_id=AWS_ACCESS_KEY_ID[1],
+                aws_secret_access_key=AWS_SECRET_ACCESS_KEY[1],
+                config=botocore.client.Config(signature_version='s3v4'),
+                region_name='us-east-1'
+            )
+            # vod_time_list = []
+            # ai消息标识所有组合标签
+            ai_all_event_type = EquipmentInfoService.get_all_comb_event_type()
+            for p in qr:
+                devUid = p['devUid']
+                eventTime = p['eventTime']
+                channel = p['Channel']
+                storage_location = p['storage_location']
+                if p['is_st'] == 1:
+                    thumbspng = '{uid}/{channel}/{time}.jpeg'.format(uid=devUid, channel=p['Channel'], time=eventTime)
                     if storage_location == 1:  # oss
-                        img = oss_img_bucket.sign_url('GET', thumbspng, 300)
-                        p['img_list'].append(img)
-                    elif region == 2 and storage_location == 2:  # 2:国内,aws
+                        response_url = oss_img_bucket.sign_url('GET', thumbspng, 300)
+                        p['img'] = response_url
+                        p['img_list'] = [response_url]
+                    elif region == 2 and storage_location == 2:  # 2:国内,aws
                         response_url = aws_s3_guonei.generate_presigned_url('get_object',
                                                                             Params={'Bucket': 'push', 'Key': thumbspng},
                                                                             ExpiresIn=300)
-                        img = response_url
-                        p['img_list'].append(img)
-                    elif region == 1 and storage_location == 2:  # 1:国外,aws
+                        p['img'] = response_url
+                        p['img_list'] = [response_url]
+                    elif region == 1 and storage_location == 2:  # 1:国外,aws
                         response_url = aws_s3_guowai.generate_presigned_url('get_object',
                                                                             Params={'Bucket': 'foreignpush',
                                                                                     'Key': thumbspng},
                                                                             ExpiresIn=300)
-                        img = response_url
-                        p['img_list'].append(img)
-            if devUid in uid_type_dict.keys():
-                p['uid_type'] = uid_type_dict[devUid]['type']
-                p['devNickName'] = uid_type_dict[devUid]['NickName']
-            else:
-                p['uid_type'] = ''
-
-            p['borderCoords'] = '' if p['borderCoords'] == '' else json.loads(p['borderCoords'])  # ai消息坐标信息
-            p['ai_event_type_list'] = []
-            if p['eventType'] in ai_all_event_type:  # 如果是ai消息类型,则分解eventType, 如:123 -> [1,2,3]
-                p['ai_event_type_list'] = list(map(int, str(p['eventType'])))
-            res.append(p)
-        return response.json(0, {'datas': res, 'count': count})
+                        p['img'] = response_url
+                        p['img_list'] = [response_url]
+
+                elif p['is_st'] == 2:
+                    # 列表装载回放时间戳标记
+                    vodqs = VodHlsModel.objects.filter(uid=devUid, channel=channel, time=int(eventTime)) \
+                        .values("bucket__bucket", "bucket__endpoint")
+                    # print(vodqs)
+                    if vodqs.exists():
+                        bucket_name = vodqs[0]['bucket__bucket']
+                        endpoint = vodqs[0]['bucket__endpoint']
+                        bucket = oss2.Bucket(auth, endpoint, bucket_name)
+                        ts = '{uid}/vod{channel}/{etime}/ts0.ts'.format(uid=devUid, channel=p['Channel'], etime=eventTime)
+                        if storage_location == 1:  # oss
+                            thumb0 = bucket.sign_url('GET', ts, 3600,
+                                                     params={'x-oss-process': 'video/snapshot,t_0000,w_700'})
+                            thumb1 = bucket.sign_url('GET', ts, 3600,
+                                                     params={'x-oss-process': 'video/snapshot,t_1000,w_700'})
+                            thumb2 = bucket.sign_url('GET', ts, 3600,
+                                                     params={'x-oss-process': 'video/snapshot,t_2000,w_700'})
+                            # thumb3 = bucket.sign_url('GET', ts, 3600, params={'x-oss-process': 'video/snapshot,t_3000,w_700'})
+                            p['img_list'] = [thumb0, thumb1, thumb2]
+                        elif region == 2 and storage_location == 2:  # 2:国内,aws
+                            thumb = aws_s3_guonei.generate_presigned_url('get_object',
+                                                                         Params={'Bucket': 'push', 'Key': ts},
+                                                                         ExpiresIn=3600)
+                            p['img_list'] = [thumb]
+                        elif region == 1 and storage_location == 2:  # 1:国外,aws
+                            thumb = aws_s3_guowai.generate_presigned_url('get_object',
+                                                                         Params={'Bucket': 'foreignpush', 'Key': ts},
+                                                                         ExpiresIn=3600)
+                            p['img_list'] = [thumb]
+                elif p['is_st'] == 3 or p['is_st'] == 4:
+                    # 列表装载回放时间戳标记
+                    p['img_list'] = []
+                    for i in range(p['is_st']):
+                        thumbspng = '{uid}/{channel}/{time}_{st}.jpeg'.format(uid=devUid, channel=p['Channel'],
+                                                                              time=eventTime, st=i)
+                        if storage_location == 1:  # oss
+                            img = oss_img_bucket.sign_url('GET', thumbspng, 300)
+                            p['img_list'].append(img)
+                        elif region == 2 and storage_location == 2:  # 2:国内,aws
+                            response_url = aws_s3_guonei.generate_presigned_url('get_object',
+                                                                                Params={'Bucket': 'push', 'Key': thumbspng},
+                                                                                ExpiresIn=300)
+                            img = response_url
+                            p['img_list'].append(img)
+                        elif region == 1 and storage_location == 2:  # 1:国外,aws
+                            response_url = aws_s3_guowai.generate_presigned_url('get_object',
+                                                                                Params={'Bucket': 'foreignpush',
+                                                                                        'Key': thumbspng},
+                                                                                ExpiresIn=300)
+                            img = response_url
+                            p['img_list'].append(img)
+                if devUid in uid_type_dict.keys():
+                    p['uid_type'] = uid_type_dict[devUid]['type']
+                    p['devNickName'] = uid_type_dict[devUid]['NickName']
+                else:
+                    p['uid_type'] = ''
+
+                p['borderCoords'] = '' if p['borderCoords'] == '' else json.loads(p['borderCoords'])  # ai消息坐标信息
+                p['ai_event_type_list'] = []
+                if p['eventType'] in ai_all_event_type:  # 如果是ai消息类型,则分解eventType, 如:123 -> [1,2,3]
+                    p['ai_event_type_list'] = list(map(int, str(p['eventType'])))
+                res.append(p)
+            return response.json(0, {'datas': res, 'count': count})
+        except Exception as e:
+            return response.json(474)
 
     def do_update_interval(self, userID, request_dict, response):
         uid = request_dict.get('uid', None)

+ 2 - 2
Controller/EquipmentManagerV2.py

@@ -326,8 +326,8 @@ class EquipmentManagerV2(View):
 
         for p in dvls:
             # 如果存在序列号返回完整序列号
-            if p['serial_number'] and p['Type'] == 101:
-                p['UID'] = CommonService.get_full_serial_number(p['UID'], p['serial_number'], p['Type'])
+            if p['serial_number']:
+                p['serial_number'] = CommonService.get_full_serial_number(p['UID'], p['serial_number'], p['Type'])
             # 新增IOT
             p['iot'] = []
             for iot in iotqs:

+ 57 - 52
Controller/EquipmentManagerV3.py

@@ -1,24 +1,23 @@
+import json
 import re
 import threading
 import time
-import traceback
 
+import base64
+import oss2
 import requests
-
-from Controller.CheckUserData import RandomStr
-import oss2, base64
 from django.db.models import Q
 from django.views.generic.base import View
+
+from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY
+from Controller.CheckUserData import RandomStr
 from Controller.DeviceConfirmRegion import Device_Region
-from Object.RedisObject import RedisObject
-from Ansjer.config import OSS_STS_ACCESS_SECRET, OSS_STS_ACCESS_KEY, BASE_DIR
-from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidPushModel, UidChannelSetModel, \
-    Device_User, iotdeviceInfoModel, UIDCompanySerialModel, UIDMainUser, UIDModel
+from Model.models import Device_Info, UID_Bucket, UID_Preview, UidSetModel, UidChannelSetModel, \
+    Device_User, iotdeviceInfoModel, UIDCompanySerialModel, UIDModel, UnicomDeviceInfo
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Service.CommonService import CommonService
 from Service.ModelService import ModelService
-import time, json
 
 
 class EquipmentManagerV3(View):
@@ -61,7 +60,7 @@ class EquipmentManagerV3(View):
         elif operation == 'fuzzyQuery':
             return self.do_fuzzy_query(userID, request_dict, response)
         elif operation == 'mainUserDevice':
-            return self.do_mainUserDevice( request_dict, response)
+            return self.do_mainUserDevice(request_dict, response)
         elif operation == 'getDeviceFeatures':
             return self.do_get_device_features(request_dict, response)
         else:
@@ -111,19 +110,18 @@ class EquipmentManagerV3(View):
         primaryMaster = ''
         isShare = False
 
-        is_bind = Device_Info.objects.filter(UID=UID, isShare=False).values('userID__userID', 'primaryUserID', 'primaryMaster')
+        is_bind = Device_Info.objects.filter(UID=UID, isShare=False).values('userID__userID', 'primaryUserID',
+                                                                            'primaryMaster')
 
         if main_exist.exists():
             vodPrimaryUserID = main_exist[0]['vodPrimaryUserID']
             vodPrimaryMaster = main_exist[0]['vodPrimaryMaster']
 
-
         if is_bind.exists():
             primaryUserID = is_bind[0]['primaryUserID']
             primaryMaster = is_bind[0]['primaryMaster']
             isShare = True
 
-
         isusermain = False
         if (vodPrimaryUserID != userID and vodPrimaryUserID != '') or (primaryUserID != userID and primaryUserID != ''):
             isusermain = True
@@ -192,8 +190,8 @@ class EquipmentManagerV3(View):
                 # 多通道设备设置通道名
                 if Type in dvr_type_list:
                     UidChannelSet_bulk = []
-                    for i in range(1, ChannelIndex+1):
-                        channel_name = 'channel'+str(i)  # channel1,channel2...
+                    for i in range(1, ChannelIndex + 1):
+                        channel_name = 'channel' + str(i)  # channel1,channel2...
                         UidChannelSet = UidChannelSetModel(uid_id=UidSet_id, channel=i, channel_name=channel_name)
                         UidChannelSet_bulk.append(UidChannelSet)
                     UidChannelSetModel.objects.bulk_create(UidChannelSet_bulk)
@@ -218,7 +216,7 @@ class EquipmentManagerV3(View):
             if us_qs.exists() and us_qs[0].is_alexa == 1:
                 if us_qs[0].channel > 1:
                     data_list = []
-                    uid_channel_set_qs = UidChannelSetModel.objects.filter(uid_id=us_qs[0].id).\
+                    uid_channel_set_qs = UidChannelSetModel.objects.filter(uid_id=us_qs[0].id). \
                         values('channel', 'channel_name')
                     if uid_channel_set_qs.exists():
                         # 多通道设备名为 UidChannelSetModel 的 channel_name
@@ -255,15 +253,13 @@ class EquipmentManagerV3(View):
             iotqs = iotdeviceInfoModel.objects.filter(serial_number=dvql[0]['serial_number'])
             if iotqs.exists():
                 res['iot'] = {
-                        'endpoint': iotqs[0].endpoint,
-                        'token_iot_number': iotqs[0].endpoint
+                    'endpoint': iotqs[0].endpoint,
+                    'token_iot_number': iotqs[0].endpoint
                 }
 
-            # 除C1的序列号暂时返回''
-            if res['serial_number'] and Type == 101:
+            # 存在序列号返回完整序列号
+            if res['serial_number']:
                 res['serial_number'] = CommonService.get_full_serial_number(UID, res['serial_number'], Type)
-            else:
-                res['serial_number'] = ''
 
             return response.json(0, res)
 
@@ -275,16 +271,16 @@ class EquipmentManagerV3(View):
             return response.json(444, {'param': 'uidContent'})
 
         try:
-            deviceNumber = 0            # 添加成功数量
-            add_success_flag = False    # 添加成功标识
-            exception_flag = False      # 异常标识
-            exists_flag = False         # 已存在标识
+            deviceNumber = 0  # 添加成功数量
+            add_success_flag = False  # 添加成功标识
+            exception_flag = False  # 异常标识
+            exists_flag = False  # 已存在标识
             uid_content_list = eval(uidContent)
             print('uidContent: ', uid_content_list)
             re_uid = re.compile(r'^[A-Za-z0-9]{14,20}$')
             for uid_content in uid_content_list:
                 exception_flag = False  # 重置异常标识
-                exists_flag = False     # 已存在标识
+                exists_flag = False  # 已存在标识
                 UID = uid_content['uid']
                 NickName = uid_content['nickName']
                 Type = uid_content['type']
@@ -297,7 +293,7 @@ class EquipmentManagerV3(View):
                 if not all([UID, NickName, View_Account]):  # Type和ChannelIndex可能为0
                     return response.json(444, {'param': 'UID, NickName, View_Account'})
 
-                if not re_uid.match(UID):   # 检查uid长度
+                if not re_uid.match(UID):  # 检查uid长度
                     return response.json(444, {'error uid length': UID})
 
                 device_info_qs = Device_Info.objects.filter(UID=UID, userID_id=userID)
@@ -321,7 +317,8 @@ class EquipmentManagerV3(View):
                 primaryMaster = ''
                 isShare = False
 
-                is_bind = Device_Info.objects.filter(UID=UID, isShare=False).values('userID__userID', 'primaryUserID', 'primaryMaster')
+                is_bind = Device_Info.objects.filter(UID=UID, isShare=False).values('userID__userID', 'primaryUserID',
+                                                                                    'primaryMaster')
 
                 if main_exist.exists():
                     vodPrimaryUserID = main_exist[0]['vodPrimaryUserID']
@@ -333,7 +330,8 @@ class EquipmentManagerV3(View):
                     isShare = True
 
                 isusermain = False
-                if (vodPrimaryUserID != userID and vodPrimaryUserID != '') or (primaryUserID != userID and primaryUserID != ''):
+                if (vodPrimaryUserID != userID and vodPrimaryUserID != '') or (
+                        primaryUserID != userID and primaryUserID != ''):
                     isusermain = True
 
                 # 判断是否有已绑定用户
@@ -400,14 +398,15 @@ class EquipmentManagerV3(View):
                     multi_channel_list = [1, 2, 3, 4, 10001]
                     if Type in multi_channel_list:
                         UidChannelSet_bulk = []
-                        for i in range(1, ChannelIndex+1):
-                            channel_name = 'channel'+str(i)  # channel1,channel2...
+                        for i in range(1, ChannelIndex + 1):
+                            channel_name = 'channel' + str(i)  # channel1,channel2...
                             UidChannelSet = UidChannelSetModel(uid_id=UidSet_id, channel=i, channel_name=channel_name)
                             UidChannelSet_bulk.append(UidChannelSet)
                         UidChannelSetModel.objects.bulk_create(UidChannelSet_bulk)
 
                 userDevice = Device_Info(id=id, userID_id=userID, UID=UID, NickName=NickName, View_Account=View_Account,
-                                         View_Password=View_Password, Type=Type, ChannelIndex=ChannelIndex, version=version,
+                                         View_Password=View_Password, Type=Type, ChannelIndex=ChannelIndex,
+                                         version=version,
                                          vodPrimaryUserID=vodPrimaryUserID, vodPrimaryMaster=vodPrimaryMaster)
                 userDevice.save()
                 uid_serial_qs = UIDCompanySerialModel.objects.filter(uid__uid=UID)
@@ -426,13 +425,14 @@ class EquipmentManagerV3(View):
                 if us_qs.exists() and us_qs[0].is_alexa == 1:
                     if us_qs[0].channel > 1:
                         data_list = []
-                        uid_channel_set_qs = UidChannelSetModel.objects.filter(uid_id=us_qs[0].id).\
+                        uid_channel_set_qs = UidChannelSetModel.objects.filter(uid_id=us_qs[0].id). \
                             values('channel', 'channel_name')
                         if uid_channel_set_qs.exists():
                             # 多通道设备名为 UidChannelSetModel 的 channel_name
                             for uid_channel_set in uid_channel_set_qs:
-                                data_list.append({'userID': userID, 'UID': UID, 'uid_nick': uid_channel_set['channel_name'],
-                                                  'channel': uid_channel_set['channel'], 'password': encryptPassword})
+                                data_list.append(
+                                    {'userID': userID, 'UID': UID, 'uid_nick': uid_channel_set['channel_name'],
+                                     'channel': uid_channel_set['channel'], 'password': encryptPassword})
                     else:
                         data_list = [{'userID': userID, 'UID': UID, 'uid_nick': NickName, 'password': encryptPassword}]
 
@@ -449,7 +449,8 @@ class EquipmentManagerV3(View):
                                                                 'vodPrimaryUserID', 'vodPrimaryMaster',
                                                                 'userID__userEmail',
                                                                 'data_joined', 'version',
-                                                                'isVod', 'isExist', 'isCameraOpenCloud', 'serial_number')
+                                                                'isVod', 'isExist', 'isCameraOpenCloud',
+                                                                'serial_number')
                 dvql = CommonService.qs_to_list(dvqs)
                 ubqs = UID_Bucket.objects.filter(uid=UID). \
                     values('bucket__content', 'status', 'channel', 'endTime', 'uid')
@@ -467,9 +468,9 @@ class EquipmentManagerV3(View):
             exception_flag = True
             pass
         finally:
-            if add_success_flag:    # 有一台添加成功则返回成功
+            if add_success_flag:  # 有一台添加成功则返回成功
                 return response.json(0, success_res)
-            if exists_flag:         # 全部设备已存在
+            if exists_flag:  # 全部设备已存在
                 return response.json(174, exists_res)
             if exception_flag:
                 return response.json(500, error_res)
@@ -579,7 +580,7 @@ class EquipmentManagerV3(View):
         dvqs = Device_Info.objects.filter(userID_id=userID)
         # # 过滤已重置的设备
         dvqs = dvqs.filter(~Q(isExist=2))
-        dvql = dvqs.values('id', 'userID', 'NickName', 'UID', 'View_Account','View_Password', 'ChannelIndex',
+        dvql = dvqs.values('id', 'userID', 'NickName', 'UID', 'View_Account', 'View_Password', 'ChannelIndex',
                            'Type', 'isShare', 'primaryUserID', 'primaryMaster', 'data_joined', 'vodPrimaryUserID',
                            'vodPrimaryMaster', 'userID__userEmail', 'version', 'isVod', 'isExist', 'NotificationMode',
                            'isCameraOpenCloud', 'serial_number')
@@ -607,7 +608,8 @@ class EquipmentManagerV3(View):
                                                                     'TimeZone', 'TimeStatus', 'SpaceUsable',
                                                                     'SpaceSum', 'MirrorType', 'RecordType',
                                                                     'OutdoorModel', 'WIFIName', 'isDetector',
-                                                                    'DetectorRank', 'is_human', 'is_custom_voice', 'is_ptz', 'double_wifi', 'is_ai')
+                                                                    'DetectorRank', 'is_human', 'is_custom_voice',
+                                                                    'is_ptz', 'double_wifi', 'is_ai', 'mobile_4g')
         uv_dict = {}
         for us in us_qs:
             uv_dict[us['uid']] = {
@@ -634,6 +636,7 @@ class EquipmentManagerV3(View):
                 'is_custom_voice': us['is_custom_voice'],
                 'is_ptz': us['is_ptz'],
                 'double_wifi': us['double_wifi'],
+                'mobile4G': us['mobile_4g'],
                 'is_ai': us['is_ai']
             }
             # 从uid_channel里面取出通道配置信息
@@ -670,14 +673,16 @@ class EquipmentManagerV3(View):
             uv_dict[us['uid']]['channels'] = channels
 
         for p in dvls:
-            # C1返回序列号
-            if p['Type'] != 101:
-                p['serial_number'] = ''
+            if p['serial_number']:
+                u_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=p['serial_number'])
+                if u_device_info_qs.exists():
+                    p['iccid'] = u_device_info_qs.first().iccid
+
             # 获取iot_deviceInfo表的endpoint和token_iot_number
             p['iot'] = []
             if p['serial_number']:  # 存在序列号根据序列号查询
                 iotdeviceInfo_qs = iotdeviceInfoModel.objects.filter(serial_number=p['serial_number'][0:6])
-            else:   # 根据uid查询
+            else:  # 根据uid查询
                 iotdeviceInfo_qs = iotdeviceInfoModel.objects.filter(uid=p['UID'])
             if iotdeviceInfo_qs.exists():
                 iotdeviceInfo = iotdeviceInfo_qs.values('endpoint', 'token_iot_number')
@@ -710,8 +715,8 @@ class EquipmentManagerV3(View):
             if p_uid in uv_dict:
                 # 设备版本号
                 uidversion = uv_dict[p_uid]['version']
-                if len(uidversion) >6:
-                    uidversion = uidversion[0 : uidversion.rfind('.')]
+                if len(uidversion) > 6:
+                    uidversion = uidversion[0: uidversion.rfind('.')]
                 p['uid_version'] = uidversion
                 p['ucode'] = uv_dict[p_uid]['ucode']
                 p['detect_interval'] = uv_dict[p_uid]['detect_interval']
@@ -735,6 +740,7 @@ class EquipmentManagerV3(View):
                 p['is_ptz'] = uv_dict[p_uid]['is_ptz']
                 p['channels'] = uv_dict[p_uid]['channels']
                 p['double_wifi'] = uv_dict[p_uid]['double_wifi']
+                p['mobile4G'] = uv_dict[p_uid]['mobile4G']
                 p['is_ai'] = uv_dict[p_uid]['is_ai']
                 # 设备昵称 调用影子信息昵称,先阶段不可
                 if uv_dict[p_uid]['nickname']:
@@ -987,16 +993,15 @@ class EquipmentManagerV3(View):
             phone = qs[0]['phone']
             username = qs[0]['username']
             qs = CommonService.qs_to_list(qs)
-            if NickName =='':
+            if NickName == '':
                 qs[0]['NickName'] = username
 
             # if userEmail =='':
             #     qs[0]['userEmail'] = NickName
 
-            if phone =='':
+            if phone == '':
                 qs[0]['phone'] = NickName
 
-
         # if not qs:
         #     uidq = UIDMainUser.objects.filter(UID=UID).values('user_id')
         #     if uidq.exists():
@@ -1027,9 +1032,9 @@ class EquipmentManagerV3(View):
             phone = qs[0]['phone']
             username = qs[0]['username']
             qs = CommonService.qs_to_list(qs)
-            if NickName =='':
+            if NickName == '':
                 qs[0]['NickName'] = username
-            if phone =='':
+            if phone == '':
                 qs[0]['phone'] = NickName
         return response.json(0, qs)
 

+ 2 - 2
Controller/OrderContrller.py

@@ -128,8 +128,8 @@ class OrderView(View):
                     d['did'] = did['id']
                     d['Type'] = did['Type']
                     # 如果存在序列号返回完整序列号
-                    if did['serial_number'] and did['Type'] == 101:
-                        d['UID'] = CommonService.get_full_serial_number(d['UID'], did['serial_number'], did['Type'])
+                    if did['serial_number']:
+                        d['serial_number'] = CommonService.get_full_serial_number(d['UID'], did['serial_number'], did['Type'])
                     data.append(d)
             d['rank__content'] = d['rank__lang__content']
             del d['rank__lang__content']

+ 27 - 0
Controller/PaymentCycle.py

@@ -5,6 +5,7 @@ from Service.CommonService import CommonService
 from django.http import JsonResponse, HttpResponseRedirect, HttpResponse
 import requests
 import time
+import datetime as date_time
 import sys
 from Object.TokenObject import TokenObject
 from Object.UidTokenObject import UidTokenObject
@@ -177,6 +178,32 @@ class PaypalCycleNotify(View):
         logger.info('----订阅详情----')
         logger.info(billing_agreement_response)
         agreement_id = billing_agreement_response.id
+        # 列出订阅的事务 https://developer.paypal.com/docs/api/subscriptions/v1/#subscriptions_transactions
+        try:
+            billing_agreement = paypalrestsdk.BillingAgreement.find(agreement_id)
+            today = date_time.date.today()
+            oneday = date_time.timedelta(days=1)
+            yesterday = today - oneday
+            start_date = yesterday.strftime('%Y-%m-%d')
+            end_date = today.strftime('%Y-%m-%d')
+            transactions = billing_agreement.search_transactions(start_date, end_date)
+            if transactions.agreement_transaction_list:
+                agreement_transaction = transactions.agreement_transaction_list[0]
+                logger.info('-->订阅首次扣款,最新一条订阅事务{}'.format(agreement_transaction))
+                if agreement_transaction.status != 'Completed':
+                    logger.info('-->首次订阅扣款状态:{}'.format(agreement_transaction.status))
+                    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)
+        except Exception as e:
+            logger.info('出错了~查询订阅的事务异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            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)
+
         order_qs = Order_Model.objects.filter(orderID=orderID, status=0)
         order_list = order_qs.values("UID", "channel", "commodity_code", "rank", "isSelectDiscounts",
                                      "userID__userID",

+ 8 - 2
Controller/SensorGateway/GatewayDeviceController.py

@@ -12,7 +12,7 @@ from django.views.generic.base import View
 
 from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
 from Model.models import FamilyRoomDevice, FamilyRoom, GatewaySubDevice, Device_Info, UserFamily, FamilyMember, \
-    UidSetModel, iotdeviceInfoModel
+    UidSetModel, iotdeviceInfoModel, SmartScene
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 
@@ -160,6 +160,7 @@ class GatewayDeviceView(View):
                         uid_set_qs = UidSetModel.objects.filter(uid=device_qs.first().UID)
                         if uid_set_qs.exists():
                             uid_set_qs.delete()
+                        SmartScene.objects.filter(device_id=device_id).delete()
                         device_qs.delete()
                 elif sub_ids:
                     sub_ids = sub_ids.split(',')
@@ -173,6 +174,7 @@ class GatewayDeviceView(View):
                     gateway_sub_qs = GatewaySubDevice.objects.filter(id__in=ids)
                     if gateway_sub_qs.exists():
                         gateway_sub_qs.delete()
+                    SmartScene.objects.filter(sub_device_id__in=ids).delete()
                 return response.json(0)
         except Exception as e:
             print(e)
@@ -228,10 +230,12 @@ class GatewayDeviceView(View):
             family_device_qs = family_device_qs.filter(~Q(sub_device=0)).order_by('-created_time')
 
             sub_device = []
+            sub_id_list = []
             if family_device_qs.exists():
                 family_device_qs = family_device_qs.values()
                 for item in family_device_qs:
                     sub_id = item['sub_device']
+                    sub_id_list.append(sub_id)
                     gateway_sub_qs = GatewaySubDevice.objects.filter(device_id=device_id, id=sub_id).values(
                         'id', 'device_type',
                         'nickname',
@@ -255,7 +259,9 @@ class GatewayDeviceView(View):
                         'ieeeAddr': gateway_sub_qs['ieee_addr'],
                         'familyId': family_id,
                     })
-            res = {'gateway': gateway, 'sub_device': sub_device, 'sub_device_count': len(sub_device), 'scene_count': 0}
+            scene_count = SmartScene.objects.filter(Q(device_id=device_id) | Q(sub_device_id__in=sub_id_list)).count()
+            res = {'gateway': gateway, 'sub_device': sub_device, 'sub_device_count': len(sub_device),
+                   'scene_count': scene_count}
             return response.json(0, res)
 
         except Exception as e:

+ 8 - 2
Controller/SensorGateway/GatewayFamilyMemberController.py

@@ -13,6 +13,7 @@ import time
 from django.db import transaction
 from django.views.generic.base import View
 
+from Ansjer.config import SERVER_DOMAIN
 from Controller.SensorGateway.EquipmentFamilyController import EquipmentFamilyView
 from Model.models import UserFamily, FamilyMemberJoin, FamilyMember, SysMsgModel, FamilyMemberPermission, \
     Device_User, FamilyRoomDevice, FamilyRoom
@@ -537,14 +538,19 @@ class GatewayFamilyMemberView(View):
         if not user_family_qs.exists():
             return response.json(173)
         user_family_qs = user_family_qs.values('id', 'name', 'user__userEmail',
-                                               'user__userIconUrl',
+                                               'user__userIconPath',
                                                'user__phone', 'user__NickName',
                                                'user__username')
+        user_icon_url = ''
+        userIconPath = str(user_family_qs[0]['user__userIconPath'])
+        if userIconPath and userIconPath.find('static/') != -1:
+            userIconPath = userIconPath.replace('static/', '').replace('\\', '/')
+            user_icon_url = SERVER_DOMAIN + 'account/getAvatar/' + userIconPath
         return response.json(0, {
             'familyId': user_family_qs[0]['id'],
             'userPhone': user_family_qs[0]['user__phone'],
             'nickName': user_family_qs[0]['user__NickName'],
-            'userIconUrl': user_family_qs[0]['user__userIconUrl'],
+            'userIconUrl': user_icon_url,
             'userName': user_family_qs[0]['user__username'],
             'familyName': user_family_qs[0]['name'],
             'userEmail': user_family_qs[0]['user__userEmail'],

+ 13 - 11
Controller/SensorGateway/GatewayFamilyRoomController.py

@@ -50,9 +50,9 @@ class GatewayFamilyRoomView(View):
         # 房间详情
         elif operation == 'details':
             return self.get_room_details(app_user_id, request_dict, response)
-        elif operation == 'all-devices':    # 家庭所有设备
+        elif operation == 'all-devices':  # 家庭所有设备
             return self.all_devices(request_dict, response)
-        elif operation == 'devices-sort':    # 家庭设备排序
+        elif operation == 'devices-sort':  # 家庭设备排序
             return self.devices_sort(request_dict, response)
         else:
             return response.json(414)
@@ -212,21 +212,23 @@ class GatewayFamilyRoomView(View):
         if not family_id:
             return response.json(444)
         try:
-            family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id, sub_device=0).\
-                annotate(type=F('device__Type'), nickname=F('device__NickName')).\
+            family_room_device_qs = FamilyRoomDevice.objects.filter(family_id=family_id, sub_device=0). \
+                annotate(type=F('device__Type'), nickname=F('device__NickName')). \
                 values('device_id', 'type', 'nickname', 'room_id').order_by('sort')
             if not family_room_device_qs.exists():
                 return response.json(0, [])
+            device_room = []
             # 查询房间名称
             for device in family_room_device_qs:
                 room_id = device['room_id']
-                if room_id == 0:
-                    device['room'] = ''
-                else:
-                    family_room_qs = FamilyRoom.objects.filter(id=room_id).values('name')
-                    device['room'] = family_room_qs[0]['name'] if family_room_qs.exists() else ''
-                device.pop('room_id')
-            return response.json(0, list(family_room_device_qs))
+                room_name = FamilyRoom.objects.filter(id=room_id)
+                device_room.append({
+                    'deviceId': device['device_id'],
+                    'deviceType': device['type'],
+                    'nickName': device['nickname'],
+                    'roomName': room_name.first().name if room_name.exists() else '',
+                })
+            return response.json(0, device_room)
         except Exception as e:
             return response.json(500, repr(e))
 

+ 687 - 0
Controller/SensorGateway/SmartSceneController.py

@@ -0,0 +1,687 @@
+# -*- coding: utf-8 -*-
+"""
+@Author : Rocky
+@Time : 2022/6/29 9:31
+@File :SmartSceneController.py
+"""
+import json
+import time
+
+from django.core.exceptions import ObjectDoesNotExist
+from django.db import transaction
+from django.db.models import F, Q
+from django.views import View
+
+from Model.models import FamilyRoomDevice, GatewaySubDevice, FamilyRoom, SmartScene, EffectiveTime, Device_Info, \
+    SceneLog
+from Service.CommonService import CommonService
+
+
+class SmartSceneView(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):
+        token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request)
+        if token_code != 0:
+            return response.json(token_code)
+        if operation == 'condition-devices':  # 添加条件-查询设备
+            return self.condition_devices(request_dict, response)
+        elif operation == 'task-devices':  # 添加任务-查询设备
+            return self.task_devices(request_dict, response)
+        elif operation == 'create':  # 创建智能场景
+            return self.create_smart_scene(request_dict, user_id, response)
+        elif operation == 'scene-list':  # 查询智能场景列表
+            return self.scene_list(request_dict, user_id, response)
+        elif operation == 'smart-button-scene-list':  # 查询智能按钮场景列表
+            return self.smart_button_scene_list(request_dict, user_id, response)
+        elif operation == 'update-status':  # 更新智能场景状态
+            return self.update_status(request_dict, response)
+        elif operation == 'detail':  # 查询智能场景详情
+            return self.scene_detail(request_dict, response)
+        elif operation == 'edit':  # 编辑智能场景
+            return self.edit_smart_scene(request_dict, user_id, response)
+        elif operation == 'delete':  # 删除智能场景
+            return self.delete_smart_scene(request_dict, response)
+        elif operation == 'log':  # 查询智能场景日志
+            return self.scene_log(request_dict, response)
+        else:
+            return response.json(414)
+
+    @classmethod
+    def condition_devices(cls, request_dict, response):
+        """
+        添加条件-查询设备
+        @param request_dict: 请求参数
+        @request_dict deviceId: 网关设备id
+        @request_dict subDeviceId: 子设备id
+        @param response: 响应对象
+        @return: response
+        """
+        device_id = request_dict.get('deviceId', None)
+        sub_device_id = request_dict.get('subDeviceId', None)
+        if not any([device_id, sub_device_id]):
+            return response.json(444, {'error param': 'deviceId or subDeviceId'})
+        try:
+            if sub_device_id:
+                device_id = GatewaySubDevice.objects.get(id=sub_device_id).device_id
+            gateway_sub_device_qs = GatewaySubDevice.objects.filter(device_id=device_id)
+            if not gateway_sub_device_qs.exists():
+                return response.json(173)
+            res = cls.get_sub_device_room_name(gateway_sub_device_qs)
+            return response.json(0, res)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @classmethod
+    def task_devices(cls, request_dict, response):
+        """
+        添加任务-查询设备
+        @param request_dict: 请求参数
+        @request_dict deviceId: 网关设备id
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('subDeviceId', None)
+        device_id = request_dict.get('deviceId', None)
+
+        if not any([device_id, sub_device_id]):
+            return response.json(444, {'error param': 'deviceId or subDeviceId'})
+        try:
+
+            if device_id:
+                res = [cls.get_gateway_data(device_id)]
+            else:
+                sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('device_id', 'device_type')
+                device_id = sub_device_qs[0]['device_id']
+                device_type = sub_device_qs[0]['device_type']
+
+                if device_type != 216:  # 非智能按钮只返回网关
+                    res = [cls.get_gateway_data(device_id)]
+                else:
+                    gateway_data = cls.get_gateway_data(device_id)
+                    sub_device_qs = GatewaySubDevice.objects.filter(
+                        Q(device_id=device_id) & Q(device_type=215) | Q(device_type=219)).values('id', 'nickname',
+                                                                                                 'status',
+                                                                                                 'device_type')
+                    if not sub_device_qs.exists():
+                        return response.json(173)
+                    res = cls.get_sub_device_room_name(sub_device_qs, gateway_data)
+
+            return response.json(0, res)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_sub_device_room_name(sub_device_qs, gateway_data=None):
+        """
+        获取房间名称
+        @param sub_device_qs: 子设备信息
+        @param gateway_data: 网关参数
+        @return: sub_device_list
+        """
+        sub_device_list = []
+        if gateway_data:
+            sub_device_list.append(gateway_data)
+        sub_device_qs = sub_device_qs.annotate(gatewaySubId=F('id'),
+                                               deviceType=F('device_type'),
+                                               deviceNickName=F('nickname')). \
+            values('gatewaySubId', 'deviceType', 'deviceNickName', 'status')
+        for sub_device in sub_device_qs:
+            family_room_device_qs = FamilyRoomDevice.objects.filter(sub_device=sub_device['gatewaySubId']). \
+                values('room_id')
+            if not family_room_device_qs.exists():
+                sub_device['roomName'] = ''
+            else:
+                room_id = family_room_device_qs[0]['room_id']
+                try:
+                    sub_device['roomName'] = FamilyRoom.objects.get(id=room_id).name
+                except ObjectDoesNotExist:
+                    sub_device['roomName'] = ''
+            sub_device_list.append(sub_device)
+        return sub_device_list
+
+    @staticmethod
+    def get_gateway_data(device_id):
+        """
+        获取网关数据
+        @param device_id: 网关设备id
+        @return: res
+        """
+        device_info_qs = Device_Info.objects.filter(id=device_id).values('NickName', 'Type')
+        nickname = device_info_qs[0]['NickName']
+        device_type = device_info_qs[0]['Type']
+        room_id = FamilyRoomDevice.objects.filter(device_id=device_id).values('room_id')[0]['room_id']
+        room_id_qs = FamilyRoom.objects.filter(id=room_id).values('name')
+        room_name = room_id_qs.first()['name'] if room_id_qs.exists() else ''
+        res = {
+            'deviceNickName': nickname,
+            'deviceType': device_type,
+            'roomName': room_name,
+            'status': 1,
+        }
+        return res
+
+    @staticmethod
+    def create_smart_scene(request_dict, user_id, response):
+        """
+        创建智能场景
+        @param request_dict: 请求参数
+        @param user_id: 用户id
+        @request_dict deviceId: 网关设备id
+        @request_dict subDeviceId: 子设备id
+        @request_dict sceneName: 场景名称
+        @request_dict conditions: 条件
+        @request_dict tasks: 任务
+        @request_dict isAllDay: 是否全天执行
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @request_dict repeat: 重复周期
+        @param response: 响应对象
+        @return: response
+        """
+        device_id = request_dict.get('deviceId', None)
+        sub_device_id = request_dict.get('subDeviceId', None)
+        scene_name = request_dict.get('sceneName', None)
+        conditions = request_dict.get('conditions', None)
+        tasks = request_dict.get('tasks', None)
+        is_all_day = request_dict.get('isAllDay', None)
+
+        if not all([scene_name, conditions, tasks]):
+            return response.json(444, {'error param': 'scene_name and conditions and tasks'})
+
+        now_time = int(time.time())
+        conditions_dict = eval(conditions)
+        tasks_list = eval(tasks)
+
+        try:
+            # 判断是否已存在该场景名
+            smart_scene_qs = SmartScene.objects.filter(user_id=user_id, scene_name=scene_name)
+            if smart_scene_qs.exists():
+                return response.json(179)
+
+            smart_scene_dict = {
+                'user_id': user_id,
+                'scene_name': scene_name,
+                'conditions': conditions,
+                'tasks': tasks,
+                'created_time': now_time,
+                'updated_time': now_time,
+            }
+            msg = {}
+            # 处理设置时间
+            if is_all_day is not None:
+                is_all_day = int(is_all_day)
+                smart_scene_dict['is_all_day'] = is_all_day
+
+            # 处理传网关设备id和子设备id的情况
+            if conditions_dict['type'] == 1:  # 网关设置时间
+                if not device_id:
+                    return response.json(444, {'error param': 'deviceId'})
+                smart_scene_dict['device_id'] = device_id
+                device_info_qs = Device_Info.objects.filter(id=device_id).values('serial_number')
+                if not device_info_qs.exists():
+                    return response.json(173)
+                serial_number = device_info_qs[0]['serial_number']
+            else:  # 子设备设置场景
+                if not sub_device_id:
+                    return response.json(444, {'error param': 'subDeviceId'})
+
+                # 智能按钮不能创建触发条件相同的场景
+                device_type = conditions_dict['sensor']['device_type']
+                if device_type == '216':
+                    event_type = conditions_dict['sensor']['eventValues'][0]['event_type']
+                    smart_scene_qs = SmartScene.objects.filter(sub_device_id=sub_device_id,
+                                                               conditions__contains=event_type)
+                    if smart_scene_qs.exists():
+                        return response.json(180)
+
+                smart_scene_dict['sub_device_id'] = sub_device_id
+                sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('device__serial_number',
+                                                                                         'src_addr')
+                if not sub_device_qs.exists():
+                    return response.json(173)
+                serial_number = sub_device_qs[0]['device__serial_number']
+                msg['scene_status'] = 1
+                msg['sensor_type'] = int(conditions_dict['sensor']['device_type'])
+                msg['sensor_src'] = int(sub_device_qs[0]['src_addr'], 16)
+                msg['sensor_status'] = int(conditions_dict['sensor']['eventValues'][0]['event_type'])
+
+            with transaction.atomic():
+                if is_all_day is None:  # 不设置时间
+                    smart_scene_qs = SmartScene.objects.create(**smart_scene_dict)
+                    # 设备的time数据,分钟转为秒
+                    time_dict = {
+                        'start_time': conditions_dict['time']['minutes'] * 60,
+                        'repeat': conditions_dict['time']['repeat']
+                    }
+                elif is_all_day == 1:  # 全天
+                    smart_scene_qs = SmartScene.objects.create(**smart_scene_dict)
+                    # 设备的time数据
+                    time_dict = {
+                        'is_all_day': is_all_day
+                    }
+                elif is_all_day == 2:  # 非全天
+                    start_time = int(request_dict.get('startTime', None))
+                    end_time = int(request_dict.get('endTime', None))
+                    repeat = int(request_dict.get('repeat', None))
+                    effective_time_qs = EffectiveTime.objects.filter(start_time=start_time, end_time=end_time,
+                                                                     repeat=repeat).values('id')
+                    if effective_time_qs.exists():
+                        effective_time_id = effective_time_qs[0]['id']
+                    else:
+                        effective_time_id = EffectiveTime.objects.create(start_time=start_time, end_time=end_time,
+                                                                         repeat=repeat).id
+                    smart_scene_dict['effective_time_id'] = effective_time_id
+                    smart_scene_qs = SmartScene.objects.create(**smart_scene_dict)
+
+                    # 设备的time数据,分钟转为秒
+                    time_dict = {
+                        'is_all_day': is_all_day,
+                        'start_time': start_time * 60,
+                        'end_time': end_time * 60,
+                        'repeat': repeat
+                    }
+                else:
+                    return response.json(444, {'error param': 'invalid isAllDay'})
+
+                msg['time'] = time_dict
+                msg['smart_scene_id'] = smart_scene_qs.id
+                task_list = []
+                for task in tasks_list:
+                    task_temp = {
+                        'sensor_type': int(task['device_type']),
+                        'sensor_action': int(task['event_type'])
+                    }
+                    sub_device_id = task.get('subDeviceId', None)
+                    if sub_device_id:
+                        sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('src_addr').first()
+                        task_temp['sensor_src'] = int(sub_device_qs['src_addr'], 16)
+                    task_list.append(task_temp)
+                msg['task'] = task_list
+
+                smart_scene_qs.device_data = json.dumps(msg)
+                smart_scene_qs.save()
+                # 发布MQTT消息通知网关设备
+                thing_name = serial_number
+                topic_name = 'loocam/gateway_sensor/smart_scene/{}'.format(serial_number)
+
+                success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
+                try:
+                    assert success
+                except AssertionError:
+                    return response.json(10044)
+
+            return response.json(0)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def scene_list(request_dict, user_id, response):
+        """
+        查询智能场景列表
+        @param request_dict: 请求参数
+        @param user_id: 用户id
+        @request_dict deviceId: 网关设备id
+        @request_dict subDeviceId: 子设备id
+        @param response: 响应对象
+        @return: response
+        """
+        device_id = request_dict.get('deviceId', None)
+        sub_device_id = request_dict.get('subDeviceId', None)
+
+        if not any([device_id, sub_device_id]):
+            return response.json(444, {'error param': 'deviceId or subDeviceId'})
+        try:
+            if device_id:
+                sub_device_id = GatewaySubDevice.objects.filter(device_id=device_id).values('id')
+                smart_scene_qs = SmartScene.objects.filter(
+                    Q(user_id=user_id) & Q(device_id=device_id) | Q(sub_device_id__in=sub_device_id))
+            else:
+                smart_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id)
+            if not smart_scene_qs.exists():
+                return response.json(173)
+            smart_scene_qs = smart_scene_qs.values('id', 'scene_name', 'is_enable')
+            return response.json(0, list(smart_scene_qs))
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def smart_button_scene_list(request_dict, user_id, response):
+        """
+        查询智能按钮场景列表
+        @param request_dict: 请求参数
+        @param user_id: 用户id
+        @request_dict subDeviceId: 子设备id
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('subDeviceId', None)
+
+        if not sub_device_id:
+            return response.json(444, {'error param': 'subDeviceId'})
+        try:
+            click_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id,
+                                                       conditions__contains='2161').values('id', 'scene_name',
+                                                                                           'is_enable')
+            double_click_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id,
+                                                              conditions__contains='2162').values('id', 'scene_name',
+                                                                                                  'is_enable')
+            press_scene_qs = SmartScene.objects.filter(user_id=user_id, sub_device_id=sub_device_id,
+                                                       conditions__contains='2163').values('id', 'scene_name',
+                                                                                           'is_enable')
+            scene_list = []
+            if click_scene_qs.exists():
+                scene_list.append({
+                    'trigger_type': 1,
+                    'id': click_scene_qs[0]['id'],
+                    'scene_name': click_scene_qs[0]['scene_name'],
+                    'is_enable': click_scene_qs[0]['is_enable']
+                })
+            if double_click_scene_qs.exists():
+                scene_list.append({
+                    'trigger_type': 2,
+                    'id': double_click_scene_qs[0]['id'],
+                    'scene_name': double_click_scene_qs[0]['scene_name'],
+                    'is_enable': double_click_scene_qs[0]['is_enable']
+                })
+            if press_scene_qs.exists():
+                scene_list.append({
+                    'trigger_type': 3,
+                    'id': press_scene_qs[0]['id'],
+                    'scene_name': press_scene_qs[0]['scene_name'],
+                    'is_enable': press_scene_qs[0]['is_enable']
+                })
+            return response.json(0, scene_list)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def update_status(request_dict, response):
+        """
+        更新智能场景状态
+        @param request_dict: 请求参数
+        @request_dict smartSceneId: 智能场景id
+        @request_dict isEnable: 状态,True or False
+        @param response: 响应对象
+        @return: response
+        """
+        smart_scene_id = request_dict.get('smartSceneId', None)
+        is_enable = request_dict.get('isEnable', None)
+
+        if not all([smart_scene_id, is_enable]):
+            return response.json(444, {'error param': 'smartSceneId and status'})
+        try:
+            SmartScene.objects.filter(id=smart_scene_id).update(is_enable=is_enable)
+            return response.json(0)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def scene_detail(request_dict, response):
+        """
+        查询智能场景详情
+        @param request_dict: 请求参数
+        @request_dict smartSceneId: 智能场景id
+        @param response: 响应对象
+        @return: response
+        """
+        smart_scene_id = request_dict.get('smartSceneId', None)
+
+        if not smart_scene_id:
+            return response.json(444, {'error param': 'smartSceneId'})
+        try:
+            smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id).values('id', 'scene_name', 'conditions',
+                                                                                 'tasks', 'effective_time_id',
+                                                                                 'is_all_day')
+            if not smart_scene_qs.exists():
+                return response.json(173)
+            res = {
+                'scene_name': smart_scene_qs[0]['scene_name'],
+                'condition': eval(smart_scene_qs[0]['conditions']),
+                'task': eval(smart_scene_qs[0]['tasks']),
+            }
+
+            # 如果存在关联的时间数据,组织时间数据
+            is_all_day = smart_scene_qs[0]['is_all_day']
+            effectiveTime = {}
+            if is_all_day != 0:
+                effectiveTime['isAllDay'] = is_all_day
+            if is_all_day == 2:
+                try:
+                    effective_time_qs = EffectiveTime.objects.get(id=smart_scene_qs[0]['effective_time_id'])
+                    effectiveTime['startTime'] = effective_time_qs.start_time
+                    effectiveTime['endTime'] = effective_time_qs.end_time
+                    effectiveTime['repeat'] = effective_time_qs.repeat
+                except ObjectDoesNotExist:
+                    return response.json(0, res)
+            res['effectiveTime'] = effectiveTime
+            return response.json(0, res)
+
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def edit_smart_scene(request_dict, user_id, response):
+        """
+        编辑智能场景
+        @param request_dict: 请求参数
+        @param user_id: 用户id
+        @request_dict smartSceneId: 智能场景id
+        @param response: 响应对象
+        @return: response
+        """
+        smart_scene_id = request_dict.get('smartSceneId', None)
+        device_id = request_dict.get('deviceId', None)
+        sub_device_id = request_dict.get('subDeviceId', None)
+        scene_name = request_dict.get('sceneName', None)
+        conditions = request_dict.get('conditions', None)
+        tasks = request_dict.get('tasks', None)
+        is_all_day = request_dict.get('isAllDay', None)
+
+        conditions_dict = eval(conditions)
+        tasks_list = eval(tasks)
+        now_time = int(time.time())
+
+        smart_scene_qs = SmartScene.objects.filter(user_id=user_id, scene_name=scene_name).filter(~Q(id=smart_scene_id))
+        if smart_scene_qs.exists():
+            return response.json(179)
+
+        res = {
+            'scene_name': scene_name,
+            'conditions': conditions_dict,
+            'tasks': tasks_list
+        }
+        effective_time = {}
+
+        if is_all_day:
+            is_all_day = int(is_all_day)
+            effective_time['is_all_day'] = is_all_day
+
+        if not all([smart_scene_id, scene_name, conditions, tasks]):
+            return response.json(444, {'error param': 'smartSceneId,sceneName,conditions or tasks'})
+        try:
+            smart_scene_qs = SmartScene.objects.filter(id=smart_scene_id)
+            if not smart_scene_qs.exists():
+                return response.json(173)
+
+            msg = {}
+            if conditions_dict['type'] == 2:  # 条件为选择子设备
+                if not sub_device_id:
+                    return response.json(444, {'error param': 'subDeviceId'})
+
+                # 智能按钮不能创建触发条件相同的场景
+                device_type = conditions_dict['sensor']['device_type']
+                if device_type == '216':
+                    event_type = conditions_dict['sensor']['eventValues'][0]['event_type']
+                    smart_scene_qs = SmartScene.objects.filter(sub_device_id=sub_device_id,
+                                                               conditions__contains=event_type)
+                    if smart_scene_qs.exists():
+                        return response.json(180)
+
+                device_id = ''
+                sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('src_addr',
+                                                                                         'device__serial_number')
+                if not sub_device_qs.exists():
+                    return response.json(173)
+                serial_number = sub_device_qs[0]['device__serial_number']
+                msg['smart_scene_id'] = smart_scene_id
+                msg['scene_status'] = 1
+                msg['sensor_type'] = conditions_dict['sensor']['device_type']
+                msg['sensor_src'] = int(sub_device_qs[0]['src_addr'], 16)
+                msg['sensor_status'] = int(conditions_dict['sensor']['eventValues'][0]['event_type'])
+            else:
+                if not device_id:
+                    return response.json(444, {'error param': 'deviceId'})
+                sub_device_id = 0
+                device_qs = Device_Info.objects.filter(id=device_id).value('serial_number')
+                if not device_qs.exists():
+                    return response.json(173)
+                serial_number = device_qs[0]['serial_number']
+
+
+            task_list = []
+            for task in tasks_list:
+                task_temp = {
+                    'sensor_type': int(task['device_type']),
+                    'sensor_action': int(task['event_type'])
+                }
+                task_sub_device_id = task.get('subDeviceId', None)
+                if task_sub_device_id:
+                    sub_device_qs = GatewaySubDevice.objects.filter(id=task_sub_device_id).values('src_addr').first()
+                    task_temp['sensor_src'] = int(sub_device_qs['src_addr'], 16)
+                task_list.append(task_temp)
+            msg['task'] = task_list
+
+            with transaction.atomic():
+                smart_scene_qs.update(scene_name=scene_name, conditions=conditions, tasks=tasks,
+                                      device_data=json.dumps(msg), updated_time=now_time, device_id=device_id,
+                                      sub_device_id=sub_device_id)
+
+                if is_all_day is None:  # 不设置时间或全天
+                    smart_scene_qs.update(effective_time_id=0, is_all_day=0)
+                    time_dict = {
+                        'start_time': conditions_dict['time']['minutes'] * 60,
+                        'repeat': conditions_dict['time']['repeat']
+                    }
+                elif is_all_day == 1:
+                    smart_scene_qs.update(effective_time_id=0, is_all_day=is_all_day)
+                    time_dict = {
+                        'is_all_day': is_all_day
+                    }
+                else:
+                    start_time = int(request_dict.get('startTime', None))
+                    end_time = int(request_dict.get('endTime', None))
+                    repeat = int(request_dict.get('repeat', None))
+                    effective_time_qs = EffectiveTime.objects.filter(start_time=start_time, end_time=end_time,
+                                                                     repeat=repeat).values('id')
+                    if effective_time_qs.exists():
+                        effective_time_id = effective_time_qs[0]['id']
+                    else:
+                        effective_time_id = EffectiveTime.objects.create(start_time=start_time, end_time=end_time,
+                                                                         repeat=repeat).id
+                    smart_scene_qs.update(effective_time_id=effective_time_id, is_all_day=is_all_day)
+                    time_dict = {
+                        'is_all_day': is_all_day,
+                        'start_time': start_time * 60,
+                        'end_time': end_time * 60,
+                        'repeat': repeat
+                    }
+                    effective_time = {
+                        'isAllDay': is_all_day,
+                        'startTime': start_time,
+                        'endTime': end_time,
+                        'repeat': repeat
+                    }
+                msg['time'] = time_dict
+
+            # 通过mqtt发送设备数据
+            thing_name = serial_number
+            topic_name = 'loocam/gateway_sensor/smart_scene/{}'.format(serial_number)
+            success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
+
+            res['effectiveTime'] = effective_time
+            return response.json(0, res)
+
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def delete_smart_scene(request_dict, response):
+        """
+        删除智能场景
+        @param request_dict: 请求参数
+        @request_dict smartSceneIds: 智能场景id
+        @param response: 响应对象
+        @return: response
+        """
+        smart_scene_ids = request_dict.get('smartSceneIds', None)
+
+        if not smart_scene_ids:
+            return response.json(444, {'error param': 'smartSceneIds'})
+        try:
+            SmartScene.objects.filter(id__in=smart_scene_ids.split(',')).delete()
+        except Exception as e:
+            return response.json(500, repr(e))
+        else:
+            return response.json(0)
+
+    @staticmethod
+    def scene_log(request_dict, response):
+        """
+        查询场景日志
+        @param request_dict: 请求参数
+        @request_dict deviceId: 网关id
+        @request_dict subDeviceId: 子设备id
+        @request_dict page: 页数
+        @request_dict size: 条数
+        @request_dict startTime: 开始时间
+        @request_dict endTime: 结束时间
+        @param response: 响应对象
+        @return: response
+        """
+        device_id = request_dict.get('deviceId', None)
+        sub_device_id = request_dict.get('subDeviceId', None)
+        page = request_dict.get('page', None)
+        size = request_dict.get('size', None)
+        start_time = request_dict.get('startTime', None)
+        end_time = request_dict.get('endTime', None)
+
+        if not any([device_id, sub_device_id]):
+            return response.json(444, {'error param': 'deviceId and subDeviceId'})
+        if not all([page, size]):
+            return response.json(444, {'error param': 'page or size'})
+
+        device_dict = {}
+        if device_id:
+            device_dict['device_id'] = device_id
+        else:
+            device_dict['sub_device_id'] = sub_device_id
+
+        try:
+            page, size = int(page), int(size)
+            if start_time and end_time:
+                scene_log_qs = SceneLog.objects.filter(**device_dict, created_time__range=(start_time, end_time)). \
+                                   values('scene_id', 'scene_log', 'status', 'created_time').order_by(
+                    '-created_time')[(page - 1) * size:page * size]
+            else:
+                scene_log_qs = SceneLog.objects.filter(**device_dict).values('scene_id', 'scene_log', 'status',
+                                                                             'created_time').order_by(
+                    '-created_time')[(page - 1) * size:page * size]
+            if not scene_log_qs.exists():
+                return response.json(0, [])
+            for item in scene_log_qs:
+                scene_id = item['scene_id']
+                scene_name = SmartScene.objects.filter(id=scene_id)[0].scene_name
+                item['scene_name'] = scene_name
+            return response.json(0, list(scene_log_qs))
+        except Exception as e:
+            print(repr(e))
+            return response.json(500, repr(e))

+ 203 - 84
Controller/SensorGateway/SubDeviceController.py

@@ -11,9 +11,7 @@ from django.db import transaction
 from django.db.models import Count
 from django.views import View
 
-from Model.models import Device_Info, GatewaySubDevice, FamilyRoomDevice, SensorRecord
-from Object.ResponseObject import ResponseObject
-from Object.TokenObject import TokenObject
+from Model.models import Device_Info, GatewaySubDevice, FamilyRoomDevice, SensorRecord, SmartScene
 from Service.CommonService import CommonService
 
 
@@ -29,13 +27,9 @@ class GatewaySubDeviceView(View):
         return self.validation(request.POST, request, operation)
 
     def validation(self, request_dict, request, operation):
-        token_obj = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
-        lang = request_dict.get('lang', None)
-        response = ResponseObject(lang if lang else token_obj.lang)
-
-        if token_obj.code != 0:
-            return response.json(token_obj.code)
-        user_id = token_obj.userID
+        token_code, user_id, response = CommonService.verify_token_get_user_id(request_dict, request)
+        if token_code != 0:
+            return response.json(token_code)
         if operation == 'add':  # 添加子设备
             return self.add_sub_device(request_dict, user_id, response)
         elif operation == 'detail':  # 查询子设备信息
@@ -43,13 +37,17 @@ class GatewaySubDeviceView(View):
         elif operation == 'update':  # 更新子设备信息
             return self.sensor_update(request_dict, response)
         elif operation == 'delete':  # 删除子设备
-            return self.delete(request_dict, user_id, response)
+            return self.delete_sub_device(request_dict, response)
         elif operation == 'records/tem-hum':  # 查询温湿度传感器记录
             return self.records_tem_hum(request_dict, response)
         elif operation == 'records':  # 查询其他传感器记录
             return self.records(request_dict, response)
         elif operation == 'records-date':  # 查询传感器记录日期
             return self.records_date(request_dict, response)
+        elif operation == 'home':  # 查询传感器主页信息
+            return self.sensor_home_info(request_dict, response)
+        elif operation == 'update-emergency-status':  # 更新智能按钮紧急开关状态
+            return self.update_emergency_status(request_dict, response)
         else:
             return response.json(414)
 
@@ -134,7 +132,9 @@ class GatewaySubDeviceView(View):
         try:
             gateway_sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('manufacturer',
                                                                                              'device_model',
-                                                                                             'mac', 'sensor_serial')
+                                                                                             'mac', 'sensor_serial',
+                                                                                             'device_type',
+                                                                                             'is_tampered')
             if not gateway_sub_device_qs.exists():
                 return response.json(173)
             res = {
@@ -143,6 +143,8 @@ class GatewaySubDeviceView(View):
                 'mac': gateway_sub_device_qs[0]['mac'],
                 'sensor_serial': gateway_sub_device_qs[0]['sensor_serial'],
             }
+            if gateway_sub_device_qs[0]['device_type'] == 216:  # 智能按钮返回紧急开关状态
+                res['emergency_status'] = gateway_sub_device_qs[0]['is_tampered']
             return response.json(0, res)
         except Exception as e:
             return response.json(500, repr(e))
@@ -177,12 +179,11 @@ class GatewaySubDeviceView(View):
             return response.json(500, repr(e))
 
     @staticmethod
-    def delete(request_dict, user_id, response):
+    def delete_sub_device(request_dict, response):
         """
         更新子设备信息
         @param request_dict: 请求参数
         @request_dict sub_device_id: 子设备id
-        @param user_id: 用户id
         @param response: 响应对象
         @return: response
         """
@@ -191,19 +192,21 @@ class GatewaySubDeviceView(View):
         if not all([sub_device_id]):
             return response.json(444)
         try:
-            GatewaySubDevice.objects.filter(id=sub_device_id).delete()
+            with transaction.atomic():
+                GatewaySubDevice.objects.filter(id=sub_device_id).delete()
+                SmartScene.objects.filter(sub_device_id=sub_device_id).delete()
             return response.json(0)
         except Exception as e:
             return response.json(500, repr(e))
 
-    @staticmethod
-    def records_tem_hum(request_dict, response):
+    @classmethod
+    def records_tem_hum(cls, request_dict, response):
         """
         查询温湿度传感器记录
         @param request_dict: 请求参数
         @request_dict gatewaySubId: 子设备id
         @request_dict cycle: 时间周期
-        @request_dict eventType: 事件类型, 18:温度,19:湿度
+        @request_dict eventType: 事件类型, 2200:温度,2201:湿度
         @param response: 响应对象
         @return: response
         """
@@ -212,75 +215,20 @@ class GatewaySubDeviceView(View):
         event_type = request_dict.get('eventType', None)
         if not all([sub_device_id, cycle, event_type]):
             return response.json(444, {'error param': 'gatewaySubId or cycle or eventType'})
+
         now_time = int(time.time())
+        # 判断event_type
+        event_type = int(event_type)
+        if event_type != 2200 and event_type != 2201:
+            return response.json(444, {'invalid eventType': event_type})
+
         try:
-            record_dict = OrderedDict()
+            record_dict = cls.get_record_dict(cycle, now_time, sub_device_id, event_type)
             record_list = []
-            if cycle == 'Hours':
-                start_time = now_time - 24 * 60 * 60
-                sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
-                                                               event_type=event_type,
-                                                               created_time__range=(start_time, now_time)). \
-                    values('alarm', 'created_time').order_by('created_time')
-                if not sensor_record_qs.exists():
-                    return response.json(0, {'records': [], 'time': now_time})
-
-                for sensor_record in sensor_record_qs:
-                    created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
-                    hour = int(created_time[-7:-5])
-                    minute = int(created_time[-4:-2])
-                    if hour != 23 and minute > 30:  # 不为23时且分钟大于30,hour+1
-                        hour += 1
-                    alarm = float(sensor_record['alarm'])
-                    # 组织数据,record_dict:{"0": [1.0, 2.0, 3.0], "1": [1.0, 2.0, 3.0]...}
-                    if str(hour) in record_dict:
-                        record_dict[str(hour)].append(alarm)
-                    else:
-                        record_dict[str(hour)] = [alarm]
-
-            elif cycle == 'Week':
-                start_time = now_time - 24 * 60 * 60 * 7
-                sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
-                                                               event_type=event_type,
-                                                               created_time__range=(start_time, now_time)). \
-                    values('alarm', 'created_time').order_by('created_time')
-                if not sensor_record_qs.exists():
-                    return response.json(0, {'records': [], 'time': now_time})
-
-                for sensor_record in sensor_record_qs:
-                    created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
-                    week = int(created_time[-1:])
-                    alarm = float(sensor_record['alarm'])
-                    # 组织数据,record_dict:{"0": [1.0, 2.0, 3.0], "1": [1.0, 2.0, 3.0]...}
-                    if str(week) in record_dict:
-                        record_dict[str(week)].append(alarm)
-                    else:
-                        record_dict[str(week)] = [alarm]
-
-            elif cycle == 'Month':
-                start_time = now_time - 24 * 60 * 60 * 30
-                sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
-                                                               event_type=event_type,
-                                                               created_time__range=(start_time, now_time)). \
-                    values('alarm', 'created_time').order_by('created_time')
-                if not sensor_record_qs.exists():
-                    return response.json(0, {'records': [], 'time': now_time})
-
-                for sensor_record in sensor_record_qs:
-                    created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
-                    month = int(created_time[:2])
-                    day = int(created_time[3:5])
-                    date = str(month) + '/' + str(day)
-                    alarm = float(sensor_record['alarm'])
-                    # 组织数据,record_dict:{"0": [1.0, 2.0, 3.0], "1": [1.0, 2.0, 3.0]...}
-                    if date in record_dict:
-                        record_dict[date].append(alarm)
-                    else:
-                        record_dict[date] = [alarm]
-
-            # 组织响应数据列表,value为每 小时/天 的平均值
-            for k, v in record_dict.items():
-                record_list.append({'key': k, 'value': round(sum(v) / len(v), 1)})
+            if record_dict:
+                # 组织响应数据列表,value为每 小时/天 的平均值
+                for k, v in record_dict.items():
+                    record_list.append({'key': k, 'value': round(sum(v) / len(v), 1)})
 
             res = {
                 'records': record_list,
@@ -290,6 +238,81 @@ class GatewaySubDeviceView(View):
         except Exception as e:
             return response.json(500, repr(e))
 
+    @staticmethod
+    def get_record_dict(cycle, now_time, sub_device_id, event_type):
+        """
+        获取记录数据
+        @param cycle: 时间周期
+        @param now_time: 当前时间
+        @param sub_device_id: 子设备id
+        @param event_type: 事件类型, 2200:温度,2201:湿度
+        @return: record_dict: 记录数据
+        """
+        record_dict = OrderedDict()
+        if cycle == 'Hours':
+            start_time = now_time - 24 * 60 * 60
+            sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                           event_type=event_type,
+                                                           created_time__range=(start_time, now_time)). \
+                values('alarm', 'created_time').order_by('created_time')
+            if not sensor_record_qs.exists():
+                return record_dict
+
+            for sensor_record in sensor_record_qs:
+                created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
+                hour = int(created_time[-7:-5])
+                minute = int(created_time[-4:-2])
+                if hour != 23 and minute > 30:  # 不为23时且分钟大于30,hour+1
+                    hour += 1
+                alarm = float(sensor_record['alarm'])
+                # 组织数据,record_dict:{"0": [1.0, 2.0, 3.0], "1": [1.0, 2.0, 3.0]...}
+                if str(hour) in record_dict:
+                    record_dict[str(hour)].append(alarm)
+                else:
+                    record_dict[str(hour)] = [alarm]
+
+        elif cycle == 'Week':
+            start_time = now_time - 24 * 60 * 60 * 7
+            sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                           event_type=event_type,
+                                                           created_time__range=(start_time, now_time)). \
+                values('alarm', 'created_time').order_by('created_time')
+            if not sensor_record_qs.exists():
+                return record_dict
+
+            for sensor_record in sensor_record_qs:
+                created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
+                week = int(created_time[-1:])
+                alarm = float(sensor_record['alarm'])
+                # 组织数据,record_dict:{"0": [1.0, 2.0, 3.0], "1": [1.0, 2.0, 3.0]...}
+                if str(week) in record_dict:
+                    record_dict[str(week)].append(alarm)
+                else:
+                    record_dict[str(week)] = [alarm]
+
+        elif cycle == 'Month':
+            start_time = now_time - 24 * 60 * 60 * 30
+            sensor_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                           event_type=event_type,
+                                                           created_time__range=(start_time, now_time)). \
+                values('alarm', 'created_time').order_by('created_time')
+            if not sensor_record_qs.exists():
+                return record_dict
+
+            for sensor_record in sensor_record_qs:
+                created_time = time.strftime('%m/%d %H:%M %w', time.localtime(sensor_record['created_time']))
+                month = int(created_time[:2])
+                day = int(created_time[3:5])
+                date = str(month) + '/' + str(day)
+                alarm = float(sensor_record['alarm'])
+                # 组织数据,record_dict:{"1/1": [1.0, 2.0, 3.0], "1/2": [1.0, 2.0, 3.0]...}
+                if date in record_dict:
+                    record_dict[date].append(alarm)
+                else:
+                    record_dict[date] = [alarm]
+
+        return record_dict
+
     @staticmethod
     def records(request_dict, response):
         """
@@ -360,3 +383,99 @@ class GatewaySubDeviceView(View):
             return response.json(0, record_date_list)
         except Exception as e:
             return response.json(500, repr(e))
+
+    @staticmethod
+    def sensor_home_info(request_dict, response):
+        """
+        查询子设备首页信息
+        @param request_dict: 请求参数
+        @request_dict gatewaySubId: 子设备id
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('gatewaySubId', None)
+        if not sub_device_id:
+            return response.json(444, {'error param': 'gatewaySubId'})
+
+        try:
+            sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id).values('device_type', 'status',
+                                                                                     'is_tampered')
+            if not sub_device_qs.exists():
+                return response.json(173)
+            scene_count = SmartScene.objects.filter(sub_device_id=sub_device_id).count()
+            res = {
+                'scene_count': scene_count,
+                'status': sub_device_qs[0]['status']
+            }
+
+            device_type = sub_device_qs[0]['device_type']
+            if device_type == 215 or device_type == 218 or device_type == 219:  # 门磁,烟雾,人体传感器返回拆动状态
+                res['is_tampered'] = sub_device_qs[0]['is_tampered']
+            elif device_type == 220:  # 温湿度传感器返回温湿度数据
+                tem_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                            event_type=2200).order_by('-created_time').values('alarm')[
+                                :1]
+                hum_record_qs = SensorRecord.objects.filter(gateway_sub_device_id=sub_device_id,
+                                                            event_type=2201).order_by('-created_time').values('alarm')[
+                                :1]
+                temperature = tem_record_qs[0]['alarm'] if tem_record_qs.exists() else ''
+                humidity = hum_record_qs[0]['alarm'] if tem_record_qs.exists() else ''
+                res['temperature'] = temperature
+                res['humidity'] = humidity
+
+            return response.json(0, res)
+        except Exception as e:
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def update_emergency_status(request_dict, response):
+        """
+        更新智能按钮紧急开关状态
+        @param request_dict: 请求参数
+        @request_dict gatewaySubId: 子设备id
+        @request_dict emergencyStatus: 紧急开关状态,0:关,1:开
+        @param response: 响应对象
+        @return: response
+        """
+        sub_device_id = request_dict.get('gatewaySubId', None)
+        emergency_status = request_dict.get('emergencyStatus', None)
+        if not all([sub_device_id, emergency_status]):
+            return response.json(444, {'error param': 'gatewaySubId or emergency_status'})
+
+        try:
+            with transaction.atomic():
+                # 更新智能按钮开关状态
+                sub_device_qs = GatewaySubDevice.objects.filter(id=sub_device_id)
+                if not sub_device_qs.exists():
+                    response.json(173)
+                sub_device_qs.update(status=emergency_status)
+
+                # 更新智能按钮场景状态
+                if emergency_status == '0':
+                    smart_scene_status = 0
+                else:
+                    smart_scene_status = 1
+                smart_scene_qs = SmartScene.objects.filter(sub_device_id=sub_device_id)
+                if not smart_scene_qs:
+                    return response.json(173)
+                smart_scene_qs.update(is_enable=smart_scene_status)
+
+            # 通过mqtt发送设备数据
+            sub_device_qs = sub_device_qs.values('device__serial_number')
+            if not sub_device_qs.exists():
+                return response.json(173)
+            serial_number = sub_device_qs[0]['device__serial_number']
+            thing_name = serial_number
+            topic_name = 'loocam/gateway_sensor/smart_scene/{}'.format(serial_number)
+            for item in smart_scene_qs:
+                msg = {
+                    'scene_id': item.id,
+                    'scene_status': item.is_enable
+                }
+
+                success = CommonService.req_publish_mqtt_msg(thing_name, topic_name, msg)
+                time.sleep(0.3)
+
+            return response.json(0)
+        except Exception as e:
+            return response.json(500, repr(e))

+ 3 - 0
Controller/ShadowController.py

@@ -102,6 +102,7 @@ def update_device_shadow(request):
         is_human = request_dict.get('is_human', None)
         is_custom_voice = request_dict.get('is_custom', None)
         double_wifi = request_dict.get('double_wifi', None)
+        mobile_4g = request_dict.get('mobile4G', None)
         is_ptz = request_dict.get('is_ptz', None)
         us_qs = UidSetModel.objects.filter(uid=uid)
         is_ai = request_dict.get('is_ai', None)
@@ -139,6 +140,8 @@ def update_device_shadow(request):
             qs_dict['is_custom_voice'] = is_custom_voice
         if double_wifi:
             qs_dict['double_wifi'] = double_wifi
+        if mobile_4g:
+            qs_dict['mobile_4g'] = int(mobile_4g)
         if is_ptz:
             qs_dict['is_ptz'] = is_ptz
         if is_ai:

+ 500 - 12
Controller/UnicomCombo/UnicomComboController.py

@@ -6,18 +6,25 @@
 @Email   : zhangdongming@asj6.wecom.work
 @Software: PyCharm
 """
+import datetime
 import json
 import logging
 import time
+import traceback
+from decimal import Decimal
 
 from django.db import transaction
-from django.http import HttpResponse
+from django.http import HttpResponse, JsonResponse
 from django.views.generic.base import View
 
-from Model.models import UnicomDeviceInfo, UnicomCombo, Pay_Type
+from Model.models import UnicomDeviceInfo, UnicomCombo, Pay_Type, Order_Model, Store_Meal, AiStoreMeal, \
+    UnicomComboOrderInfo, UnicomComboExperienceHistory, UnicomDeviceStatusChangePush, SysMsgModel, UnicomFlowPush
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
 from Object.UnicomObject import UnicomObjeect
+from Object.utils import LocalDateTimeUtil
+from Object.utils.PayUtil import PayService
+from Service.CommonService import CommonService
 
 
 class UnicomComboView(View):
@@ -32,25 +39,226 @@ class UnicomComboView(View):
         return self.validation(request.POST, request, operation)
 
     def validation(self, request_dict, request, operation):
-        if operation == 'buy-notify':
-            return self.package_callback_notify(request_dict, request)
+        response = ResponseObject('cn')
+        if operation == 'query-usage-history':
+            return self.query_device_usage_history(request_dict, response)
+        elif operation == 'test-notify':
+            order_id = request_dict.get('orderId', None)
+            activate_type = request_dict.get('activateType', 0)
+            iccid = request_dict.get('iccid', None)
+            combo_id = request_dict.get('comboId', None)
+            self.create_combo_order_info(order_id, int(activate_type), iccid, int(combo_id))
+            return HttpResponse('SUCCESS')
         elif operation == 'device-queue-monitoring':
             return self.device_queue_monitoring_push(request_dict, request)
         elif operation == 'device-status-change':
             return self.device_status_change_push(request_dict, request)
         elif operation == 'device-bind':
-            response = ResponseObject('cn')
             return self.device_add(request_dict, response)
+        elif operation == 'device-status':
+            return self.update_device_status(request_dict, response)
+        elif operation == 'xxx-sign':
+            return self.get_test_sign(request_dict, response)
         else:
             token = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
             lang = request_dict.get('lang', token.lang)
             response = ResponseObject(lang)
             if token.code != 0:
                 return response.json(token.code)
+            user_id = token.userID
             if operation == 'combo-save':
                 return self.save_unicom_combo(request_dict, response)
+            elif operation == 'combo-pay':
+                return self.buy_unicom_combo(user_id, request_dict, request, response)
             elif operation == 'combo-list':
                 return self.query_package_list(response)
+            elif operation == 'get-device-info':
+                return self.get_device_info(request_dict, response)
+            elif operation == 'user-combo-query':
+                return self.user_combo_query(user_id, request_dict, response)
+
+    @classmethod
+    def user_combo_query(cls, user_id, request_dict, response):
+        """
+        查询套餐流量列表与正在使用流量详情
+        @param user_id:
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        try:
+            iccid = request_dict.get('iccid', None)
+            if not iccid:
+                return response.json(444)
+            unicom_device_info_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
+            if not unicom_device_info_qs.exists():
+                return response.json(173)
+            if not unicom_device_info_qs[0].user_id:
+                unicom_device_info_qs.update(user_id=user_id)
+            unicom_api = UnicomObjeect()
+            today = datetime.datetime.today()
+            year = today.year
+            month = today.month
+            combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid, status=1, is_del=False) \
+                .values('iccid', 'status', 'combo__status', 'combo__combo_name', 'combo__combo_type',
+                        'combo__flow_total', 'combo__remark', 'combo__expiration_days', 'combo__expiration_type',
+                        'year', 'month', 'flow_total_usage', 'expire_time', 'activation_time', 'combo__is_unlimited')
+            if combo_order_qs.exists():
+                combo_order = combo_order_qs.first()
+                flow_details = {
+                    'flowInvalid': 0,
+                    'iccid': iccid,
+                    'status': combo_order['status'],
+                    'isUnlimited': combo_order['combo__is_unlimited'],
+                    'comboName': combo_order['combo__combo_name'],
+                    'comboType': combo_order['combo__combo_type'],
+                    'flowTotal': combo_order['combo__flow_total'],
+                    'comboRemark': combo_order['combo__remark'],
+                    'expirationDays': combo_order['combo__expiration_days'],
+                    'expirationType': combo_order['combo__expiration_type'],
+                    'flowTotalUsage': combo_order['flow_total_usage'],
+                    'activationTime': combo_order['activation_time'],
+                    'expireTime': combo_order['expire_time'],
+                    'year': combo_order['year'],
+                    'month': combo_order['month'],
+                }
+                if flow_details['year'] == year and flow_details['month'] == month:
+                    month_flow = unicom_api.get_flow_usage_total(year, month, iccid)
+                    # 当月流量减去 套餐激活时用量
+                    month_flow = month_flow - float(flow_details['flowTotalUsage'])
+                    flow = flow_details['flowTotal'] - month_flow
+                    flow_details['usableFlow'] = flow
+                else:
+                    now_month_flow = unicom_api.get_flow_usage_total(year, month, iccid)
+                    last_month_flow = unicom_api.get_flow_usage_total(flow_details['year'], flow_details['month'],
+                                                                      iccid)
+                    flow = now_month_flow + last_month_flow - float(flow_details['flowTotalUsage'])
+                    flow_details['usableFlow'] = flow_details['flowTotal'] - flow
+
+                flow_details['usableFlow'] = \
+                    0.00 if flow_details['usableFlow'] <= 0 else flow_details['usableFlow']
+                flow_details['usableFlow'] = Decimal(flow_details['usableFlow']).quantize(Decimal('0.00'))
+                flow_details.pop('flowTotalUsage')
+                cls.update_combo_order_sort(iccid)
+                flow_details['comboList'] = cls.get_combo_order_list(iccid)
+                return response.json(0, flow_details)
+            else:
+                flow_details = {'iccid': iccid, 'flowInvalid': 1, 'comboList': cls.get_combo_order_list(iccid)}
+                cls.update_combo_order_sort(iccid)
+                return response.json(0, flow_details)
+        except Exception as e:
+            print(e.args)
+            ex = traceback.format_exc()
+            print(ex)
+            return response.json(177, ex)
+
+    @classmethod
+    def get_combo_order_list(cls, iccid):
+        """
+        查询套餐列表
+        @param iccid:
+        @return:
+        """
+        combo_list = []
+        combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid, is_del=False) \
+            .values('iccid', 'status', 'combo__combo_name', 'combo__flow_total',
+                    'combo__remark', 'combo__expiration_days', 'combo__expiration_type', 'flow_total_usage',
+                    'expire_time', 'combo__is_unlimited').order_by('sort')
+        for item in combo_order_qs:
+            combo_list.append({
+                'iccid': iccid,
+                'status': item['status'],
+                'comboName': item['combo__combo_name'],
+                'isUnlimited': item['combo__is_unlimited'],
+                'flowTotal': item['combo__flow_total'],
+                'comboRemark': item['combo__remark'],
+                'expirationDays': item['combo__expiration_days'],
+                'expirationType': item['combo__expiration_type'],
+                'expireTime': item['expire_time'],
+            })
+        return combo_list
+
+    @classmethod
+    def update_combo_order_sort(cls, iccd):
+        """
+        修改套餐排序
+        @param iccd: 联通20位ICCID
+        @return:
+        """
+        combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccd, is_del=False)
+        if combo_order_qs.exists():
+            unused_qs = combo_order_qs.filter(status=0)
+            if unused_qs.exists():
+                unused_qs.update(sort=50)
+            used_qs = combo_order_qs.filter(status=1)
+            if used_qs.exists():
+                used_qs.update(sort=1)
+            expire_qs = combo_order_qs.filter(status=2)
+            if expire_qs.exists():
+                expire_qs.update(sort=100)
+
+    @classmethod
+    def update_device_status(cls, request_dict, response):
+        """
+        修改绑定设备状态,如产生免费套餐用量则删除
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        logger = logging.getLogger('info')
+
+        serial_no = request_dict.get('serialNo', None)
+        iccid = request_dict.get('iccid', None)
+        time_stamp = request_dict.get('timeStamp', None)
+        sign = request_dict.get('sign', None)
+        if not all([iccid, serial_no, sign, time_stamp]):
+            return response.json(444)
+        logger.info('PC工具进入重置ICCID{}'.format(iccid))
+        try:
+            if not CommonService.check_time_stamp_token(sign, time_stamp):
+                return response.json(13)
+            now_time = int(time.time())
+            with transaction.atomic():
+                device_info_qs = UnicomDeviceInfo.objects.filter(iccid=iccid, serial_no=serial_no)
+                if device_info_qs.exists():
+                    flow_push_qs = UnicomFlowPush.objects.filter(serial_no=serial_no)
+                    if flow_push_qs.exists():
+                        flow_push_qs.delete()
+                    sys_msg_qs = SysMsgModel.objects.filter(uid=serial_no)
+                    if sys_msg_qs.exists():
+                        sys_msg_qs.delete()
+                    device_info_qs.update(status=1, updated_time=now_time, user_id='')
+
+                    combo_order_qs = UnicomComboOrderInfo.objects.filter(iccid=iccid)
+                    if combo_order_qs.exists():
+                        combo_order_qs.delete()
+                    combo_experience_history_qs = UnicomComboExperienceHistory.objects.filter(iccid=iccid)
+                    if combo_experience_history_qs.exists():
+                        combo_experience_history_qs.delete()
+
+                return response.json(0)
+        except Exception as e:
+            print(e.args)
+            ex = traceback.format_exc()
+            print(ex)
+            logger.info('PC工具重置异常ICCID{},msg={}'.format(iccid, ex))
+            return response.json(177, ex)
+
+    @classmethod
+    def get_device_info(cls, request_dict, response):
+        """
+        获取设备信息
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        serial_no = request_dict.get('serialNumber', None)
+        if not serial_no:
+            return response.json(444)
+        unicom_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no).values()
+        if not unicom_device_info_qs.exists():
+            return response.json(173)
+        return response.json(0, dict(unicom_device_info_qs.first()))
 
     @classmethod
     def device_add(cls, request_dict, response):
@@ -62,14 +270,24 @@ class UnicomComboView(View):
         """
         iccid = request_dict.get('iccid', None)
         serial_no = request_dict.get('serialNo', None)
-        if not all([iccid, serial_no]):
+        time_stamp = request_dict.get('timeStamp', None)
+        sign = request_dict.get('sign', None)
+        logger = logging.getLogger('info')
+        logger.info('--->设备调用4G注册接口')
+        if not all([iccid, serial_no, sign, time_stamp]):
             return response.json(444)
+            # 时间戳token校验
+        if not CommonService.check_time_stamp_token(sign, time_stamp):
+            return response.json(13)
         n_time = int(time.time())
         try:
+            logger.info('--->参数验证通过,sign验证通过')
             with transaction.atomic():
                 # 待完善代码 根据uid与用户id验证系统设备
                 unicom_device_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
                 if unicom_device_qs.exists():
+                    if unicom_device_qs.first().status == 1 and unicom_device_qs.first().serial_no == serial_no:
+                        cls.user_activate_flow(iccid)
                     return response.json(174)
                 unicom_obj = UnicomObjeect()
                 result = unicom_obj.verify_device(iccid=iccid)
@@ -80,14 +298,57 @@ class UnicomComboView(View):
                             return response.json(173)
                         params = {'iccid': iccid, 'serial_no': serial_no, 'updated_time': n_time,
                                   'created_time': n_time}
+                        unicom_obj.change_device_to_activate(iccid)
                         UnicomDeviceInfo.objects.create(**params)
                     return response.json(0)
                 else:
                     return response.json(173)
         except Exception as e:
             print(e)
+            logger.info('--->设备调用4G注册接口异常')
             return response.json(177, repr(e))
 
+    @classmethod
+    def user_activate_flow(cls, iccid):
+        """
+        用户激活初始化流量套餐
+        @param iccid:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            while transaction.atomic():
+                now_time = int(time.time())
+                unicom_device_info_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
+                if not unicom_device_info_qs.exists():
+                    return False
+                unicom_device_info_qs = unicom_device_info_qs.first()
+                if unicom_device_info_qs.status != 1:
+                    logger.info('---->用户激活iccid={},业务系统状态为{}'.format(iccid, unicom_device_info_qs.status))
+                    return False
+                # 联通业务逻辑
+                unicom_api = UnicomObjeect()
+                unicom_api.change_device_to_activate(iccid)
+                # 查看是否体验过免费套餐
+                experience_history_qs = UnicomComboExperienceHistory.objects.filter(iccid=iccid)
+                if not experience_history_qs.exists():
+                    logger.info('---->用户首次激活iccid={}'.format(iccid))
+                    combo_qs = UnicomCombo.objects.filter(combo_type=1, status=0, is_del=False) \
+                        .values('id', 'expiration_type', 'expiration_days', 'combo_type')
+                    if combo_qs.exists():
+                        combo_qs = combo_qs.first()
+                        # 保存体验记录
+                        experience_history_vo = {'iccid': iccid, 'experience_type': 0, 'do_time': now_time}
+                        UnicomComboExperienceHistory.objects.create(**experience_history_vo)
+                        # 保存套餐激活信息
+                        cls.create_combo_order_info('', 0, iccid, combo_qs['id'])
+                # 修改业务联通卡设备激活信息
+                UnicomDeviceInfo.objects.filter(iccid=iccid).update(status=2, updated_time=now_time)
+                return True
+        except Exception as e:
+            print(e)
+            return False
+
     @classmethod
     def save_unicom_combo(cls, request_dict, response):
         """
@@ -165,19 +426,106 @@ class UnicomComboView(View):
             return response.json(177, repr(e))
 
     @classmethod
-    def buy_package(cls):
+    def buy_unicom_combo(cls, user_id, request_dict, request, response):
+        """
+        购买联通套餐
+        @return:
+        """
+        try:
+            with transaction.atomic():
+                iccid = request_dict.get('iccid', None)
+                combo_id = request_dict.get('id', None)
+                pay_type = request_dict.get('payType', None)
+                activate_type = request_dict.get('activateType', 0)
+                if not all([iccid, combo_id, pay_type]):
+                    return response.json(444)
+                combo_id = int(combo_id)
+                pay_type = int(pay_type)
+                now_time = int(time.time())
+                unicom_combo_qs = UnicomCombo.objects.filter(id=combo_id, pay_type=pay_type, is_show=1, is_del=False,
+                                                             status=0) \
+                    .values('id', 'combo_name', 'price', 'remark')
+                if not unicom_combo_qs.exists():
+                    return response.json(173)
+                unicom_device_qs = UnicomDeviceInfo.objects.filter(iccid=iccid) \
+                    .values('serial_no')
+                if not unicom_device_qs.exists():
+                    return response.json(173)
+                unicom_combo_qs = unicom_combo_qs.first()
+                price = unicom_combo_qs['price']
+                if not price:
+                    return response.json(173)
+                unicom_device_qs = unicom_device_qs.first()
+                device_uid = CommonService.query_uid_with_serial(unicom_device_qs['serial_no'])
+                order_id = CommonService.createOrderID()
+                rank_id, ai_rank_id = cls.get_cloud_or_ai_combo()
+
+                order_dict = {'rank_id': rank_id, 'ai_rank_id': ai_rank_id, 'orderID': order_id, 'UID': device_uid,
+                              'userID_id': user_id, 'desc': unicom_combo_qs['combo_name'], 'payType': pay_type,
+                              'payTime': now_time, 'price': price, 'currency': 'CNY', 'addTime': now_time,
+                              'updTime': now_time,
+                              'unify_combo_id': str(unicom_combo_qs['id']), 'order_type': 2,
+                              }
+
+                params = 'lang=cn' + '&activateType=' + activate_type
+                result = {'result_code': 0, 'reason': 'success', 'error_code': 0}
+                if pay_type == 2:  # 支付宝
+                    pay_price = PayService.get_two_float(price, 2)
+                    notify_url = 'unicom/wap/pay/ali-notify'
+
+                    order_dict['pay_url'] = PayService.create_alipay_payment(params, order_id, pay_price,
+                                                                             unicom_combo_qs['combo_name'],
+                                                                             notify_url,
+                                                                             unicom_combo_qs['remark'], response)
+                    res_data = {'redirectUrl': order_dict['pay_url'], 'orderID': order_id}
+                elif pay_type == 3:  # 微信支付
+                    notify_url = 'unicom/wap/pay/wechat-notify'
+                    ip = CommonService.get_ip_address(request)
+                    params = 'activateType=' + activate_type
+                    sign_params = PayService.create_wechat_payment(params, order_id,
+                                                                   price, ip,
+                                                                   notify_url,
+                                                                   unicom_combo_qs['remark'],
+                                                                   response)
+                    result['result'] = sign_params
+                else:
+                    return response.json(444, {'param': 'pay_type'})
+
+                Order_Model.objects.create(**order_dict)
+                if pay_type == 3:
+                    return JsonResponse(status=200, data=result)
+                return response.json(0, res_data)
+        except Exception as e:
+            print(e)
+            return response.json(500, repr(e))
+
+    @staticmethod
+    def get_cloud_or_ai_combo():
         """
-        购买套餐
+        获取云存或者AI套餐id
         @return:
         """
-        pass
+        rank_id = Store_Meal.objects.all().order_by('sort').values().first()['id']
+        ai_rank_id = AiStoreMeal.objects.all().values().first()['id']
+        return rank_id, ai_rank_id
 
     @classmethod
-    def query_device_usage_history(cls):
+    def query_device_usage_history(cls, request_dict, response):
         """
         查询用量历史
         @return:
         """
+        today = datetime.datetime.today()
+        year = today.year
+        month = today.month
+        year = request_dict.get('year', year)
+        month = request_dict.get('month', month)
+        iccid = request_dict.get('iccid', None)
+        if not iccid:
+            return response.json(444)
+        unicom_api = UnicomObjeect()
+        flow = unicom_api.get_flow_usage_total(int(year), int(month), iccid)
+        return response.json(0, flow)
 
     @staticmethod
     def package_callback_notify(request_dict, request):
@@ -254,11 +602,151 @@ class UnicomComboView(View):
                 dict_data.pop('sign')
                 unicom_obj = UnicomObjeect()
                 generate_sign = unicom_obj.createSign(**dict_data)
-                logger.info('设备状态变更推送请求签名{}'.format(sign))
-                logger.info('设备状态变更推送生成签名{}'.format(generate_sign))
+                logger.info('联通设备状态变更推送请求签名{}'.format(sign))
+                logger.info('联通设备状态变更推送生成签名{}'.format(generate_sign))
+                assert generate_sign == sign
+                now_time = int(time.time())
+                re_data = {
+                    'iccid': dict_data['iccid'],
+                    'serial_no': dict_data['serialNo'],
+                    'sign': sign,
+                    'type': dict_data['type'],
+                    'previous_val': dict_data['previousVal'],
+                    'current_val': dict_data['currentVal'],
+                    'reason': dict_data['reason'],
+                    'time': dict_data['time'],
+                    'updated_time': now_time,
+                    'created_time': now_time
+                }
+                UnicomDeviceStatusChangePush.objects.create(**re_data)
             r_data = {'success': True, 'msg': '成功'}
             return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
         except Exception as e:
             print(repr(e))
             r_data = {'success': False, 'msg': '失败'}
             return HttpResponse(json.dumps(r_data, ensure_ascii=False), content_type="application/json,charset=utf-8")
+
+    @classmethod
+    def create_combo_order_info(cls, order_id, activate_type, iccid, combo_id):
+        """
+        创建套餐生效记录
+        @param order_id: 订单id
+        @param activate_type: 激活类型
+        @param iccid: 联通20位iccid
+        @param combo_id: 套餐id
+        @return: True Or False
+        """
+        logger = logging.getLogger('info')
+        logger.info('创建联通订单套餐信息,订单id{}'.format(order_id))
+        try:
+            today = datetime.datetime.today()
+            year = today.year
+            month = today.month
+            with transaction.atomic():
+                unicom_combo_qs = UnicomCombo.objects.filter(id=int(combo_id)).values()
+                if unicom_combo_qs.exists():
+                    unicom_combo = unicom_combo_qs.first()
+                    now_time = int(time.time())
+                    combo_order_qs = UnicomComboOrderInfo.objects.filter(status=1, iccid=iccid)
+                    status = 0
+                    if not combo_order_qs.exists():
+                        status = 1
+                    combo_order_data = {'iccid': iccid, 'status': status, 'combo_id': int(combo_id),
+                                        'updated_time': now_time,
+                                        'created_time': now_time,
+                                        'year': year, 'month': month}
+                    if order_id:
+                        combo_order_data['order_id'] = order_id
+                    # 有效期类型 1 等于自然月,0天数
+                    if unicom_combo['expiration_type'] == 1:
+                        # 激活类型 1=下月激活 否则等于当月激活
+                        if activate_type == 1:
+                            combo_order_data['next_month_activate'] = True
+                            next_start_time, end_time = cls.get_next_month_data_time()
+                            combo_order_data['activation_time'] = next_start_time
+                            combo_order_data['expire_time'] = end_time
+                            combo_order_data['status'] = 0
+                        else:
+                            start_time, month_end_time = cls.get_month_start_and_end_time()
+                            combo_order_data['activation_time'] = now_time
+                            combo_order_data['expire_time'] = month_end_time
+
+                    elif unicom_combo['expiration_type'] == 0:
+                        days = unicom_combo['expiration_days']
+                        zero_today, end_time = cls.get_data_time(days)
+                        combo_order_data['activation_time'] = now_time
+                        combo_order_data['expire_time'] = end_time
+                        # 联通业务逻辑
+                    unicom_api = UnicomObjeect()
+                    if status == 1:
+                        unicom_api.change_device_to_activate(iccid)
+                        flow_total_usage = unicom_api.get_flow_usage_total(year, month, iccid)
+                        if flow_total_usage > 0:
+                            flow_total_usage = Decimal(flow_total_usage)
+                            flow_total_usage = flow_total_usage.quantize(Decimal('0.00'))
+                        else:
+                            flow_total_usage = 0
+                        combo_order_data['flow_total_usage'] = str(flow_total_usage)
+                    UnicomComboOrderInfo.objects.create(**combo_order_data)
+                    logger.info('保存套餐支付信息success')
+                return True
+        except Exception as e:
+            print(e)
+            return False
+
+    @staticmethod
+    def get_next_month_data_time():
+        """
+        获取下个月开始时间与结束时间戳
+        @return: next_start_time,end_time
+        """
+        next_month_start = LocalDateTimeUtil.get_next_month_start()
+        next_start_time, next_end_time = LocalDateTimeUtil.get_start_and_end_time(next_month_start, '%Y-%m-%d')
+        next_month_end = LocalDateTimeUtil.get_next_month_end()
+        start_time, end_time = LocalDateTimeUtil.get_start_and_end_time(next_month_end, '%Y-%m-%d')
+        return next_start_time, end_time
+
+    @staticmethod
+    def get_data_time(days):
+        """
+        获取今天开始时间以及days后日期结束时间戳
+        @return: next_start_time,end_time
+        """
+        zero_today, last_today = LocalDateTimeUtil.get_today_date(True)
+        now_time = int(time.time())
+        after_time = LocalDateTimeUtil.get_after_days_timestamp(now_time, days)
+        time_array = time.localtime(after_time)
+        start_time, end_time = LocalDateTimeUtil.get_start_and_end_time(time.strftime("%Y-%m-%d", time_array),
+                                                                        '%Y-%m-%d')
+        return zero_today, end_time
+
+    @staticmethod
+    def get_month_start_and_end_time():
+        """
+        获取当天开始时间与当月结束时间戳
+        @return:
+        """
+        zero_today, last_today = LocalDateTimeUtil.get_today_date(True)
+        month_end = LocalDateTimeUtil.get_cur_month_end()
+        start_time, month_end_time = LocalDateTimeUtil.get_start_and_end_time(month_end, '%Y-%m-%d')
+        return zero_today, month_end_time
+
+    @classmethod
+    def get_test_sign(cls, request_dict, response):
+        """
+        测试盐加密解密
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        verify = request_dict.get('verify', False)
+        if verify:
+            sign = request_dict.get('sign')
+            time_stamp = request_dict.get('timeStamp')
+            sign = CommonService.check_time_stamp_token(sign, time_stamp)
+            if not sign:
+                return response.json(13)
+            return response.json(0)
+        now_time = int(time.time())
+        sign = CommonService.encode_data(str(now_time))
+        return response.json(0, {'sign': sign, 'timeStamp': now_time})

+ 189 - 0
Controller/UnicomCombo/UnicomComboPayNotifyController.py

@@ -0,0 +1,189 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : UnicomComboPayNotifyController.py
+@Time    : 2022/6/29 14:31
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import logging
+import time
+from urllib.parse import parse_qs, unquote
+
+from django.db import transaction
+from django.http import HttpResponse
+from django.views import View
+
+from Controller.UnicomCombo.UnicomComboController import UnicomComboView
+from Model.models import Order_Model, UnicomDeviceInfo
+from Object.AliPayObject import AliPayObject
+from Object.RedisObject import RedisObject
+from Object.WechatPayObject import WechatPayObject
+from Service.CommonService import CommonService
+
+
+class UnicomComboPayNotifyView(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):
+        if operation == 'ali-notify':
+            return self.alipay_notify(request_dict)
+        elif operation == 'wechat-notify':
+            return self.wechat_notify(request)
+
+    @classmethod
+    def alipay_notify(cls, request_dict):
+        """
+        支付宝网页支付异步回调通知
+        参考文档 https://opendocs.alipay.com/open/203/105286
+        @param request_dict: 请求参数
+        @return: success or fail
+        """
+        logger = logging.getLogger('info')
+        logger.info('联通套餐支付---支付宝支付回调')
+        order_id = ''
+        redisObj = RedisObject()
+        notify_key = 'ansjer:unicom:alipay:{}:str'
+        try:
+            re_data = request_dict.dict()
+            passback_params = re_data['passback_params']
+            params = dict([(k, v[0]) for k, v in parse_qs(unquote(passback_params)).items()])
+            activate_type = int(params['activateType'])
+            logger.info('支付宝异步回调参数:{},携带参数{}', re_data, params)
+            signature = re_data['sign']
+            re_data.pop('sign')
+            order_id = re_data['out_trade_no']
+
+            # redis加锁,防止订单重复  命令在指定的 key 不存在时,为 key 设置指定的值。存在则返回0
+            isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1)
+            # 过期时间60秒
+            redisObj.CONN.expire(notify_key.format(order_id), 60)
+            if not isLock:
+                return HttpResponse('fail')
+
+            order_qs = Order_Model.objects.filter(orderID=order_id)
+            if not order_qs.exists():
+                logger.info('系统订单不存在:{}'.format(order_id))
+                return HttpResponse('fail')
+            order_qs = order_qs.filter(status=0)
+            if not order_qs.exists():
+                logger.info('订单已支付或退款{}'.format(order_id))
+                return HttpResponse('success')
+            aliPayObj = AliPayObject()
+            alipay = aliPayObj.conf()
+            # 异步回调验签
+            success = alipay.verify(re_data, signature)
+            if not success or re_data["trade_status"] not in ("TRADE_SUCCESS", "TRADE_FINISHED"):
+                return HttpResponse('fail')
+            return cls.order_pay_notify(order_id, re_data["trade_no"], activate_type, notify_key.format(order_id),
+                                        order_qs, redisObj)
+        except Exception as e:
+            logger.info('联通套餐订单支付宝支付回调异常:{}'.format(repr(e)))
+            redisObj.del_data(key=notify_key.format(order_id))
+            return HttpResponse('fail')
+
+    @classmethod
+    def wechat_notify(cls, request):
+        """
+        微信支付异步回调
+        参考文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_1
+        @param request: 回调参数 具体参考:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_7&index=8
+        @return: SUCCESS or FAIL
+        """
+        logger = logging.getLogger('info')
+        logger.info('联通套餐支付---微信支付回调')
+        order_id = ''
+        redisObj = RedisObject()
+        notify_key = 'ansjer:unicom:wxpay:{}:str'
+        pay = WechatPayObject()
+        try:
+            re_data = pay.weixinpay_call_back(request.body)
+            attach = re_data["attach"]
+            parmap = dict([(k, v[0]) for k, v in parse_qs(unquote(attach)).items()])
+            activate_type = int(parmap['activateType'])
+            logger.info('微信异步回调参数:{},携带参数{}'.format(re_data, parmap))
+            trade_status = re_data['result_code']  # 业务结果  SUCCESS/FAIL
+            order_id = re_data['out_trade_no']  # 商户订单号
+            order_qs = Order_Model.objects.filter(orderID=order_id)
+            if not order_qs.exists():
+                return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
+            order_qs = order_qs.filter(status=0)
+            if not order_qs.exists():
+                logger.info('订单已支付或退款{}'.format(order_id))
+                return cls.wx_return_code()
+
+            if trade_status != 'SUCCESS':
+                logger.info('微信支付回调Fail')
+                order_qs.update(status=10)
+                return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
+            check_sign = pay.get_notifypay(re_data)
+            if not check_sign:
+                logger.info('微信支付回调签名失败')
+                return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': '签名失败'}))
+
+            # redis加锁,防止订单重复
+            redisObj = RedisObject()
+            isLock = redisObj.CONN.setnx(notify_key.format(order_id), 1)
+            redisObj.CONN.expire(notify_key.format(order_id), 60)
+            if not isLock:
+                return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL'}))
+
+            return cls.order_pay_notify(order_id, re_data["transaction_id"], activate_type, notify_key.format(order_id),
+                                        order_qs,
+                                        redisObj, True)
+        except Exception as e:
+            redisObj.del_data(key=notify_key.format(order_id))
+            return HttpResponse(pay.xml_to_dict({'return_code': 'FAIL', 'return_msg': repr(e)}))
+
+    @staticmethod
+    def wx_return_code():
+        return HttpResponse("<xml>\
+                                  <return_code><![CDATA[SUCCESS]]></return_code>\
+                                  <return_msg><![CDATA[OK]]></return_msg>\
+                              </xml>")
+
+    @classmethod
+    def order_pay_notify(cls, order_id, trade_no, activate_type, request_key, order_qs, redisObj, is_wechat_pay=False):
+        """
+        订单支付通知
+        @param trade_no: 第三方交易流水号
+        @param order_id:订单编号
+        @param activate_type: 激活类型
+        @param request_key:访问缓存key
+        @param order_qs:订单对象
+        @param redisObj:缓存对象
+        @param is_wechat_pay:是否微信支付
+        @return: success or fail
+        """
+        logger = logging.getLogger('info')
+        now_time = int(time.time())
+        with transaction.atomic():
+            # 支付宝交易凭证号。
+            order_qs = order_qs.values('UID', 'unify_combo_id', 'userID_id', 'order_type')
+            device_uid = order_qs[0]['UID']
+            combo_id = order_qs[0]['unify_combo_id']
+            serial_no = CommonService.query_serial_with_uid(device_uid)
+            unicom_device_info_qs = UnicomDeviceInfo.objects.filter(serial_no=serial_no).values('iccid')
+            if unicom_device_info_qs.exists():
+                iccid = unicom_device_info_qs[0]['iccid']
+                UnicomComboView.create_combo_order_info(order_id, activate_type,
+                                                        iccid, combo_id)
+            order_qs.update(trade_no=trade_no, status=1, payTime=now_time, updTime=now_time)
+            logger.info('购买联通套餐成功,序列号为:{}'.format(serial_no))
+        redisObj.del_data(key=request_key)
+        if is_wechat_pay:
+            return HttpResponse("<xml>\
+                          <return_code><![CDATA[SUCCESS]]></return_code>\
+                          <return_msg><![CDATA[OK]]></return_msg>\
+                        </xml>")
+        else:
+            return HttpResponse('success')

+ 291 - 0
Controller/UnicomCombo/UnicomComboTaskController.py

@@ -0,0 +1,291 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : UnicomComboTaskController.py
+@Time    : 2022/6/30 16:23
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+import datetime
+import logging
+import time
+from decimal import Decimal
+
+from django.db import transaction
+from django.db.models import Q
+from django.views import View
+
+from Model.models import UnicomComboOrderInfo, UnicomCombo, Order_Model, UnicomDeviceInfo, UnicomFlowPush
+from Object.ResponseObject import ResponseObject
+from Object.UnicomObject import UnicomObjeect
+
+
+class UnicomComboTaskView(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()
+        print(request)
+        if operation == 'check-activate':
+            return self.check_activate_combo(request_dict, response)
+        elif operation == 'check-flow':
+            return self.check_flow_usage(response)
+        elif operation == 'check-flow-expire':
+            return self.check_flow_expire(response)
+        elif operation == 'check-expire':
+            today = datetime.datetime.today()
+            year = today.year
+            month = today.month
+            self.query_unused_combo_and_activate(request_dict.get('iccid'), year, month, '666')
+            return response.json(0)
+
+    @classmethod
+    def check_activate_combo(cls, request_dict, response):
+        """
+        定时检查是否有次月激活套餐
+        @param request_dict:
+        @param response:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        print(request_dict)
+        logger.info('--->进入监控次月激活联通套餐')
+        now_time = int(time.time())
+        combo_order_info_qs = UnicomComboOrderInfo.objects.filter(status=0, next_month_activate=True,
+                                                                  activation_time__lte=now_time,
+                                                                  expire_time__gte=now_time, is_del=0).values()
+        if not combo_order_info_qs.exists():
+            return response.json(0)
+        try:
+            today = datetime.datetime.today()
+            year = today.year
+            month = today.month
+            with transaction.atomic():
+                unicom_api = UnicomObjeect()
+                for item in combo_order_info_qs:
+                    if item['order_id']:
+                        order_id = item['order_id']
+                        order_qs = Order_Model.objects.filter(orderID=order_id, status=1)
+                        if not order_qs.exists():
+                            continue
+                        combo_order_qs = UnicomComboOrderInfo.objects.filter(status=1, iccid=item['iccid'])
+                        # 当前已有套餐正在使用则跳出当前循环
+                        if combo_order_qs.exists():
+                            continue
+                        combo_id = item['combo_id']
+                        combo_qs = UnicomCombo.objects.filter(id=combo_id).values()
+                        if not combo_qs.exists():
+                            continue
+                        # 查询当月用量情况
+                        flow_total_usage = unicom_api.get_flow_usage_total(year, month, item['iccid'])
+                        flow_total_usage = Decimal(flow_total_usage).quantize(
+                            Decimal('0.00')) if flow_total_usage > 0 else 0
+                        flow_total_usage = str(flow_total_usage)
+                        iccid = item['iccid']
+                        # 检查激活iccid
+                        unicom_api.change_device_to_activate(iccid)
+                        cls.query_unused_combo_and_activate(iccid, year, month, flow_total_usage)
+                        logger.info('激活成功,订单编号:{}'.format(order_id))
+            return response.json(0)
+        except Exception as e:
+            logger.info('出错了~次月激活套餐异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(177, repr(e))
+
+    @classmethod
+    def check_flow_usage(cls, response):
+        """
+        检查流量使用情况
+        @return:
+        """
+        logger = logging.getLogger('info')
+        logger.info('--->进入监控流量使用情况')
+        try:
+            unicom_api = UnicomObjeect()
+            combo_order_qs = UnicomComboOrderInfo.objects.filter(status=1, is_del=False, combo__is_unlimited=0).values()
+            if not combo_order_qs.exists():
+                return response.json(0)
+            today = datetime.datetime.today()
+            year = today.year
+            month = today.month
+            now_time = int(time.time())
+            for item in combo_order_qs:
+                iccid = item['iccid']
+                u_device_info_qs = UnicomDeviceInfo.objects.filter(iccid=iccid)
+                if not u_device_info_qs.exists():
+                    continue
+                u_device_info_qs = u_device_info_qs.first()
+                usage_flow = float(item['flow_total_usage']) if item['flow_total_usage'] else 0.0
+                combo_id = item['combo_id']
+                combo_qs = UnicomCombo.objects.filter(id=combo_id).values()
+                if not combo_qs.exists():
+                    continue
+                combo_qs = combo_qs.first()
+                flow_total = combo_qs['flow_total']
+                # 查询当前月用量历史
+                month_usage_flow = unicom_api.get_flow_usage_total(year, month, iccid)
+                logger.info('--->{}-{},iccid:{};套餐总值:{},激活时当月用量值:{},月已用量:{}'
+                            .format(year, month, iccid, flow_total, usage_flow, month_usage_flow))
+                is_expire = False
+                if item['year'] == year and item['month'] == month:
+                    if month_usage_flow > 0:
+                        # 初始套餐已使用流量 + 套餐总流量
+                        flow = usage_flow + flow_total
+                        if month_usage_flow >= flow:
+                            is_expire = True
+                    usage = (month_usage_flow - usage_flow) if month_usage_flow > usage_flow else 0
+                    cls.flow_warning_push(u_device_info_qs.user_id, u_device_info_qs.serial_no, item['id'], flow_total,
+                                          usage)
+                else:
+                    activate_year = item['year']
+                    activate_month = item['month']
+                    # 上月使用流量
+                    last_usage_flow = unicom_api.get_flow_usage_total(activate_year, activate_month, iccid)
+                    # 上月套餐实际使用量
+                    actual_usage_flow = last_usage_flow - usage_flow
+                    # 剩余
+                    surplus_flow = flow_total - actual_usage_flow
+                    if month_usage_flow > 0:
+                        if month_usage_flow >= surplus_flow:
+                            is_expire = True
+                    usage = (month_usage_flow + last_usage_flow - usage_flow) \
+                        if (month_usage_flow + last_usage_flow) > usage_flow else 0
+                    cls.flow_warning_push(u_device_info_qs.user_id, u_device_info_qs.serial_no, item['id'], flow_total,
+                                          usage)
+                # 检查是否有当月未使用套餐 没有则停卡
+                if is_expire:
+                    UnicomComboOrderInfo.objects.filter(id=item['id']).update(status=2, updated_time=now_time)
+                    activate_status = cls.query_unused_combo_and_activate(iccid, year, month,
+                                                                          month_usage_flow)
+                    if not activate_status:
+                        # 停用
+                        unicom_api.change_device_to_disable(iccid)
+
+            return response.json(0)
+        except Exception as e:
+            logger.info('出错了~检测流量用量详情异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return response.json(177, repr(e))
+
+    @staticmethod
+    def flow_warning_push(app_user_id, serial_no, combo_order_id, flow_total, flow_usage):
+        """
+        监控流量使用大于85%and小于96%进行消息推送提醒
+        @param app_user_id: app用户id
+        @param serial_no: 序列号
+        @param combo_order_id: 当前套餐订单id
+        @param flow_total: 流量总量
+        @param flow_usage: 已使用流量
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            if not app_user_id:
+                return False
+            if 0 < flow_total and 0 < flow_usage < flow_total:
+                res = flow_usage / flow_total * 100
+                if 85 < res <= 95:
+                    flow_push = UnicomFlowPush.objects.filter(serial_no=serial_no, combo_order_id=combo_order_id)
+                    if not flow_push.exists():
+                        now_time = int(time.time())
+                        push_data = {'combo_order_id': str(combo_order_id), 'serial_no': serial_no,
+                                     'flow_total_usage': flow_usage, 'flow_total': flow_total, 'status': 0,
+                                     'updated_time': now_time,
+                                     'created_time': now_time, 'user_id': app_user_id}
+                        UnicomFlowPush.objects.create(**push_data)
+            return True
+        except Exception as e:
+            logger.info('出错了~异常流量监控,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+    @staticmethod
+    def query_unused_combo_and_activate(iccid, year, month, usage_flow):
+        """
+        查询未使用套餐并激活
+        @param iccid:
+        @param year:
+        @param month:
+        @param usage_flow:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        try:
+            now_time = int(time.time())
+            combo_order_qs = UnicomComboOrderInfo.objects \
+                .filter(expire_time__gt=now_time, activation_time__lte=now_time, status=0, iccid=iccid) \
+                .order_by('created_time')
+            if not combo_order_qs.exists():
+                return False
+
+            combo_order = combo_order_qs.first()
+            if not combo_order.order_id:
+                return False
+            order_qs = Order_Model.objects.filter(orderID=combo_order.order_id, status=1)
+            if not order_qs.exists():
+                return False
+            upd_data = {
+                'status': 1,
+                'year': year,
+                'month': month,
+                'flow_total_usage': str(usage_flow),
+                'updated_time': now_time,
+            }
+            UnicomComboOrderInfo.objects.filter(id=combo_order.id).update(**upd_data)
+            return True
+        except Exception as e:
+            logger.info('出错了~检测流量用量详情异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+            return False
+
+    @classmethod
+    def check_flow_expire(cls, response):
+        """
+        检查流量到期停卡操作
+        @param response:
+        @return:
+        """
+        logger = logging.getLogger('info')
+        logger.info('--->进入监控流量到期停卡或激活叠加包')
+        now_time = int(time.time())
+        combo_order_qs = UnicomComboOrderInfo.objects.filter(~Q(status=2), expire_time__lte=now_time,
+                                                             is_del=False).values()
+        today = datetime.datetime.today()
+        year = today.year
+        month = today.month
+        if not combo_order_qs.exists():
+            return response.json(0)
+        iccid_list = []
+        with transaction.atomic():
+            for item in combo_order_qs:
+                try:
+                    icc_id = item['iccid']
+                    um_device_qs = UnicomDeviceInfo.objects.filter(iccid=icc_id)
+                    if not um_device_qs.exists():
+                        continue
+                    UnicomComboOrderInfo.objects.filter(id=item['id']).update(status=2)
+                    iccid_list.append(icc_id)
+                    logger.info('--->当前流量套餐已过期,iccid:{}'.format(icc_id))
+                except Exception as e:
+                    logger.info('出错了~监控流量到期异常,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+                    continue
+        # set无序不重复元素集
+        iccid_list = list(set(iccid_list))
+        unicom_api = UnicomObjeect()
+        for item in iccid_list:
+            activate_combo_qs = UnicomComboOrderInfo.objects.filter(iccid=item, status=1, expire_time__gt=now_time,
+                                                                    is_del=False).values()
+            if activate_combo_qs.exists():
+                continue
+            usage_flow = unicom_api.get_flow_usage_total(year, month, item)
+            result = cls.query_unused_combo_and_activate(item, year, month, usage_flow)
+            if not result:
+                # 停用设备
+                unicom_api.change_device_to_disable(item)
+            else:
+                unicom_api.change_device_to_activate(item)
+        return response.json(0)

+ 126 - 82
Controller/UserController.py

@@ -11,44 +11,47 @@
 @file: UserController.py
 @Contact: chanjunkai@163.com
 """
+import base64
 import datetime
-import traceback
-import time
 import logging
+import random
+import threading
+import time
+import traceback
+from io import BytesIO
+
 import jwt
+import requests
 import simplejson
 import simplejson as json
-import requests
+from PIL import Image, ImageDraw, ImageFont
 from django.contrib.auth.hashers import make_password, check_password  # 对密码加密模块
 from django.db.models import Q
 from django.http import HttpResponseRedirect
+from django.shortcuts import HttpResponse
 from django.utils.decorators import method_decorator
 from django.utils.timezone import utc
 from django.views.decorators.csrf import csrf_exempt
 from django.views.generic import TemplateView
+from django.views.generic import View
 from jwt.algorithms import RSAAlgorithm
 from ratelimit.decorators import ratelimit
 
 from Ansjer.config import AuthCode_Expire, SERVER_DOMAIN, APNS_CONFIG, JPUSH_CONFIG, FCM_CONFIG, TUTK_PUSH_DOMAIN
+from Ansjer.config import BASE_DIR
 from Controller.CheckUserData import DataValid, date_handler, RandomStr
 from Model.models import Device_User, Role, UidPushModel, UserOauth2Model, UserExModel, Device_Info, UidSetModel, \
-    UserAppFrequencyModel, CountryIPModel, CountryModel, UidChannelSetModel, Order_Model, UID_Bucket, Unused_Uid_Meal
+    UserAppFrequencyModel, CountryIPModel, CountryModel, UidChannelSetModel, Order_Model, UID_Bucket, Unused_Uid_Meal, \
+    GatewayPush
 from Object.AWS.SesClassObject import SesClassObject
 from Object.AliSmsObject import AliSmsObject
 from Object.RedisObject import RedisObject
 from Object.ResponseObject import ResponseObject
 from Object.TokenObject import TokenObject
+from Object.UVerifyObject import UVerifyObject
 from Service.CommonService import CommonService
 from Service.ModelService import ModelService
 from Service.TemplateService import TemplateService
-from django.views.generic import View
-import base64
-import random
-from io import BytesIO
-from PIL import Image, ImageDraw, ImageFont
-from django.shortcuts import HttpResponse
-from Ansjer.config import BASE_DIR
-from Object.UVerifyObject import UVerifyObject
 
 
 # 获取验证码
@@ -290,6 +293,7 @@ class registerView(TemplateView):
         else:
             return response.json(109)
 
+
 # 登出
 class LogoutView(TemplateView):
     @method_decorator(csrf_exempt)
@@ -310,24 +314,19 @@ class LogoutView(TemplateView):
         response = ResponseObject()
         token = request_dict.get('token')
         tko = TokenObject(token)
-        if tko.code == 0:
-            Device_User.objects.filter(userID=tko.userID).update(online=False)
-
-            redisObj = RedisObject(db=3)
-            redisObj.del_data(key=tko.userID)
-            m_code = request_dict.get('m_code', None)
-            if m_code:
-                userID = tko.userID
-                try:
-                    UidPushModel.objects.filter(userID_id=userID, m_code=m_code).delete()
-                except Exception as e:
-                    pass
-                else:
-                    pass
-            return response.json(0)
-        else:
+        if tko.code != 0:
             return response.json(tko.code)
 
+        Device_User.objects.filter(userID=tko.userID).update(online=False)
+        redisObj = RedisObject(db=3)
+        redisObj.del_data(key=tko.userID)
+        m_code = request_dict.get('m_code', None)
+        if m_code:
+            userID = tko.userID
+            UidPushModel.objects.filter(userID_id=userID, m_code=m_code).delete()
+            GatewayPush.objects.filter(user_id=userID, m_code=m_code).update(logout=True)
+        return response.json(0)
+
 
 # 修改密码
 class ChangePwdView(TemplateView):
@@ -709,7 +708,7 @@ class refreshTokenViewV3(TemplateView):
             userID = tko.userID
             tko.lang = lang
 
-            if password:     # 检验密码
+            if password:  # 检验密码
                 password = password.strip()
                 # 解密
                 for i in range(1, 4):
@@ -903,8 +902,8 @@ class v2authCodeView(TemplateView):
             msg = res["Message"]
             if code == "isv.MOBILE_NUMBER_ILLEGAL":
                 if response.lang == "cn":
-                    msg = phone+"非法手机"
-            return response.json(10,msg)
+                    msg = phone + "非法手机"
+            return response.json(10, msg)
 
     def phoneCodeV2(self, country_code, phone, response, sign_name):
         dataValid = DataValid()
@@ -1975,28 +1974,28 @@ class v3LoginView(TemplateView):
         else:
             data_valid = DataValid()
             if data_valid.email_validate(username):
-                return self.do_email_login(username, password, response, subscribe, number)
+                return self.do_email_login(username, password, response, subscribe, number, request_dict)
             elif data_valid.mobile_validate(username):
-                return self.do_phone_login(username, password, response, subscribe, number)
+                return self.do_phone_login(username, password, response, subscribe, number, request_dict)
             elif data_valid.name_validate(username):
-                return self.do_name_login(username, password, response, subscribe, number)
+                return self.do_name_login(username, password, response, subscribe, number, request_dict)
             else:
                 return response.json(107)
 
-    def do_email_login(self, email, password, response, subscribe, number):
+    def do_email_login(self, email, password, response, subscribe, number, request_dict):
         user_qs = Device_User.objects.filter(Q(username=email) | Q(userEmail=email))
-        return self.valid_login(user_qs, password, response, subscribe, number)
+        return self.valid_login(user_qs, password, response, subscribe, number, request_dict)
 
-    def do_phone_login(self, phone, password, response, subscribe, number):
+    def do_phone_login(self, phone, password, response, subscribe, number, request_dict):
         user_qs = Device_User.objects.filter(Q(phone=phone) | Q(username=phone), is_active=True, user_isValid=True)
-        return self.valid_login(user_qs, password, response, subscribe, number)
+        return self.valid_login(user_qs, password, response, subscribe, number, request_dict)
 
-    def do_name_login(self, username, password, response, subscribe, number):
+    def do_name_login(self, username, password, response, subscribe, number, request_dict):
         user_qs = Device_User.objects.filter(Q(username=username) | Q(phone=username) | Q(userEmail=username),
                                              is_active=True, user_isValid=True)
-        return self.valid_login(user_qs, password, response, subscribe, number)
+        return self.valid_login(user_qs, password, response, subscribe, number, request_dict)
 
-    def valid_login(self, user_qs, password, response, subscribe, number):
+    def valid_login(self, user_qs, password, response, subscribe, number, request_dict):
         if not user_qs.exists():
             return response.json(104)
         # users = user_qs.values('role__rid', 'role__roleName', 'userID', 'role', 'NickName', 'username', 'userEmail',
@@ -2005,9 +2004,11 @@ class v3LoginView(TemplateView):
             user_qs.update(subscribe_email=subscribe)
 
         users = user_qs.values('role__rid', 'role__roleName', 'userID', 'NickName', 'username', 'userEmail',
-                               'phone', 'password', 'userIconPath', 'fingerprint_enable', 'fingerprint_key', 'subscribe_email')[0]
+                               'phone', 'password', 'userIconPath', 'fingerprint_enable', 'fingerprint_key',
+                               'subscribe_email')[0]
         if not check_password(password, users['password']):
             return response.json(111)
+
         userID = users['userID']
         tko = TokenObject()
         res = tko.generate(
@@ -2017,36 +2018,49 @@ class v3LoginView(TemplateView):
         if oauth_qs.exists():
             auth_type = oauth_qs[0].authType
 
+        if tko.code != 0:
+            return response.json(tko.code)
 
-        if tko.code == 0:
-            now_time = datetime.datetime.utcnow().replace(tzinfo=utc).astimezone(utc)
-            if not number:
-                user_qs.update(last_login=now_time, language=response.lang)
+        # 网关推送新增内容
+        app_bundle_id = request_dict.get('appBundleId', None)
+        app_type = request_dict.get('appType', None)
+        push_type = request_dict.get('pushType', None)
+        token_val = request_dict.get('tokenVal', None)
+        m_code = request_dict.get('mCode', None)
+        lang = request_dict.get('language', 'en')
+        tz = request_dict.get('tz', None)
+        if all([app_bundle_id, app_type, push_type, token_val, m_code, tz]):
+            gateway_push_qs = GatewayPush.objects.filter(user_id=userID, m_code=m_code)
+            if gateway_push_qs.exists():
+                gateway_push_qs.update(token_val=token_val, logout=False)
             else:
-                user_qs.update(last_login=now_time, language=response.lang, region_country=number)
+                GatewayPush.objects.create(user_id=userID, app_bundle_id=app_bundle_id, app_type=app_type,
+                                           push_type=push_type, token_val=token_val, m_code=m_code, lang=lang, tz=tz)
 
-            res['rid'] = users['role__rid']
-            res['roleName'] = users['role__roleName']
-            res['permList'] = ModelService.own_permission(userID)
-            res['userID'] = userID
-            # 昵称,邮箱,电话,刷新,头像
-            userIconPath = str(users['userIconPath'])
-            if userIconPath and userIconPath.find('static/') != -1:
-                userIconPath = userIconPath.replace('static/', '').replace('\\', '/')
-                res['userIconUrl'] = SERVER_DOMAIN + 'account/getAvatar/' + userIconPath
-            else:
-                res['userIconUrl'] = ''
-            res['NickName'] = users['NickName'] if users['NickName'] is not None else ''
-            res['username'] = users['username'] if users['username'] is not None else ''
-            res['userEmail'] = users['userEmail'] if users['userEmail'] is not None else ''
-            res['phone'] = users['phone'] if users['phone'] is not None else ''
-            # res['fingerprint_enable'] = users['fingerprint_enable']
-            # res['fingerprint_key'] = CommonService.encode_data(content=users['fingerprint_key'], start=2)
-            res['authType'] = auth_type
-            res['subscribe_email'] = users['subscribe_email'] if users['subscribe_email'] is not None else ''
-            return response.json(0, res)
+        now_time = datetime.datetime.utcnow().replace(tzinfo=utc).astimezone(utc)
+        if not number:
+            user_qs.update(last_login=now_time, language=response.lang)
         else:
-            return response.json(tko.code)
+            user_qs.update(last_login=now_time, language=response.lang, region_country=number)
+
+        res['rid'] = users['role__rid']
+        res['roleName'] = users['role__roleName']
+        res['permList'] = ModelService.own_permission(userID)
+        res['userID'] = userID
+        # 昵称,邮箱,电话,刷新,头像
+        userIconPath = str(users['userIconPath'])
+        if userIconPath and userIconPath.find('static/') != -1:
+            userIconPath = userIconPath.replace('static/', '').replace('\\', '/')
+            res['userIconUrl'] = SERVER_DOMAIN + 'account/getAvatar/' + userIconPath
+        else:
+            res['userIconUrl'] = ''
+        res['NickName'] = users['NickName'] if users['NickName'] is not None else ''
+        res['username'] = users['username'] if users['username'] is not None else ''
+        res['userEmail'] = users['userEmail'] if users['userEmail'] is not None else ''
+        res['phone'] = users['phone'] if users['phone'] is not None else ''
+        res['authType'] = auth_type
+        res['subscribe_email'] = users['subscribe_email'] if users['subscribe_email'] is not None else ''
+        return response.json(0, res)
 
 
 # 一键登录接口
@@ -2078,7 +2092,8 @@ class oneClickLoginView(TemplateView):
             if not phone:
                 return response.json(102)
 
-            user_qs = Device_User.objects.filter(phone=phone).values('userID', 'username', 'NickName', 'phone', 'password')
+            user_qs = Device_User.objects.filter(phone=phone).values('userID', 'username', 'NickName', 'phone',
+                                                                     'password')
             # 用户已存在的响应
             if user_qs.exists():
                 tokenObj = TokenObject()
@@ -2194,6 +2209,9 @@ class InitInfoView(View):
                     return response.json(904)
             else:
                 return response.json(444, 'push_type')
+            asy = threading.Thread(target=self.save_push_config,
+                                   args=(userID, appBundleId, push_type, token_val, m_code, lang, tz))
+            asy.start()
             if m_code:
                 # 获取设备推送状态
                 update_dict = {
@@ -2237,6 +2255,31 @@ class InitInfoView(View):
         res = {'usmsg': 0}  # 预留字段, 有版本app该字段去掉会报错
         return response.json(0, res)
 
+    @staticmethod
+    def save_push_config(user_id, app_bundle_id, push_type, token_val, m_code, lang, tz):
+        """
+        异步保存新推送配置
+        @param user_id: 用户id
+        @param app_bundle_id: app版本包id
+        @param push_type: 推送类型 0:Ios,1:Google,2:国内极光
+        @param token_val: 推送token
+        @param m_code: 手机唯一标识
+        @param lang: 语言
+        @param tz: 时区
+        @return: None
+        """
+        try:
+            app_type = 1 if push_type == 0 else 2
+            gateway_push_qs = GatewayPush.objects.filter(user_id=user_id, m_code=m_code)
+            if gateway_push_qs.exists():
+                gateway_push_qs.update(token_val=token_val, logout=False)
+            else:
+                GatewayPush.objects.create(user_id=user_id, app_bundle_id=app_bundle_id, app_type=app_type,
+                                           push_type=push_type, token_val=token_val, m_code=m_code, lang=lang, tz=tz)
+        except Exception as e:
+            print('出错了~异步保存配置信息错误,errLine:{}, errMsg:{}'.format(e.__traceback__.tb_lineno, repr(e)))
+
+
     def update_country(self, request_dict, response, request):
         username = request_dict.get('unique', None)
         appBundleId = request_dict.get('appBundleId', None)
@@ -3066,7 +3109,8 @@ class alexaUidView(TemplateView):
                 uid_list.append(UID)
                 uid_dict[UID] = {'nick': uid_q['NickName'], 'password': uid_q['View_Password']}
 
-            us_qs = UidSetModel.objects.filter(uid__in=uid_list, is_alexa=1).values('id', 'uid', 'region_alexa', 'channel')
+            us_qs = UidSetModel.objects.filter(uid__in=uid_list, is_alexa=1).values('id', 'uid', 'region_alexa',
+                                                                                    'channel')
             if not us_qs.exists():
                 return response.json(173)
             # uid,password,region的列表
@@ -3081,7 +3125,8 @@ class alexaUidView(TemplateView):
 
                 # 多通道设备获取通道名
                 if channel > 1:
-                    uid_channel_set_qs = UidChannelSetModel.objects.filter(uid_id=us['id']).values('channel', 'channel_name')
+                    uid_channel_set_qs = UidChannelSetModel.objects.filter(uid_id=us['id']).values('channel',
+                                                                                                   'channel_name')
                     if uid_channel_set_qs.exists():
                         # DVR设备名为 UidChannelSetModel 的 channel_name
                         for uid_channel_set in uid_channel_set_qs:
@@ -3098,6 +3143,7 @@ class alexaUidView(TemplateView):
         except Exception as e:
             return response.json(500, repr(e))
 
+
 # 登出
 class V2LogoutView(TemplateView):
     @method_decorator(csrf_exempt)
@@ -3604,7 +3650,6 @@ class v3LoginByCodeView(View):
         if oauth_qs.exists():
             auth_type = oauth_qs[0].authType
 
-
         if tko.code == 0:
             now_time = datetime.datetime.utcnow().replace(tzinfo=utc).astimezone(utc)
             user_qs.update(last_login=now_time, language=response.lang)
@@ -4059,6 +4104,7 @@ def updateUserCountry(request):
     response = ResponseObject()
     return response.json(0)
 
+
 def confirmRegion(request):
     response = ResponseObject()
     request.encoding = 'utf-8'
@@ -4069,17 +4115,17 @@ def confirmRegion(request):
     number = request.POST.get('number', None)
     selectRegion = CountryModel.objects.filter(number=number).values('region__api')
     if not selectRegion.exists():
-        return response.json(0,{"request_url":"https://www.dvema.com"})
+        return response.json(0, {"request_url": "https://www.dvema.com"})
     else:
-        return response.json(0,{"request_url":selectRegion[0]['region__api']})
+        return response.json(0, {"request_url": selectRegion[0]['region__api']})
 
 
 def deleteAccount(request):
     response = ResponseObject()
     request.encoding = 'utf-8'
-    #test
-    token = request.POST.get('token',None)
-    password = request.POST.get('userPwd',None)
+    # test
+    token = request.POST.get('token', None)
+    password = request.POST.get('userPwd', None)
     try:
         for i in range(1, 4):
             if i == 1:
@@ -4125,8 +4171,8 @@ def deleteAccount(request):
         if hasDevices.exists():
             return response.json(10047)
 
-        orderUserIds = Order_Model.objects.filter(userID=userID,status=1).values_list('UID').distinct().order_by("UID")
-        hadUseSevice = UID_Bucket.objects.filter(uid__in=orderUserIds,use_status=1)
+        orderUserIds = Order_Model.objects.filter(userID=userID, status=1).values_list('UID').distinct().order_by("UID")
+        hadUseSevice = UID_Bucket.objects.filter(uid__in=orderUserIds, use_status=1)
         if hadUseSevice.exists():
             return response.json(10046)
 
@@ -4173,7 +4219,7 @@ class InitUserInformationView(View):
             now_time = int(time.time())
             if user_ex_qs.exists():
                 update = {
-                    'appBundleId':appBundleId,
+                    'appBundleId': appBundleId,
                     'updTime': now_time
                 }
                 user_ex_qs.update(**update)
@@ -4184,5 +4230,3 @@ class InitUserInformationView(View):
             return response.json(0)
         else:
             return response.json(444)
-
-

+ 123 - 7
Model/models.py

@@ -1184,6 +1184,7 @@ class UidSetModel(models.Model):
     is_human = models.IntegerField(default=0, verbose_name='是否支持人形追踪。0:不支持,1:支持')
     is_custom_voice = models.IntegerField(default=0, verbose_name='是否支持自定义语音。0:不支持,1:支持')
     double_wifi = models.IntegerField(default=0, verbose_name='是否支持双频wifi。0:不支持,1:支持')
+    mobile_4g = models.IntegerField(default=0, verbose_name='是否支持4g。0:不支持,1:支持')
     is_ptz = models.IntegerField(default=0, verbose_name='是否支持云台。0:不支持,1:支持')
     is_ai = models.IntegerField(default=2, verbose_name='是否支持ai')  # 0,关闭,1开启,2,不支持
     is_notification = models.IntegerField(blank=True, default=1, verbose_name='新加-消息提醒开关')  # 0:关闭,1:开启
@@ -1218,6 +1219,25 @@ class UidPushModel(models.Model):
         ordering = ('-id',)
 
 
+class GatewayPush(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增id')
+    user_id = models.CharField(default='', max_length=32, verbose_name=u'用户id')
+    app_bundle_id = models.CharField(default='', max_length=32, verbose_name=u'app包id')
+    app_type = models.IntegerField(default=0, verbose_name=u'app类型')  # 1: ios, 2: 安卓
+    push_type = models.IntegerField(default=0, verbose_name=u'推送类型')  # 0: apns, 1: 安卓gcm, 2: 极光
+    token_val = models.CharField(default='', max_length=500, verbose_name=u'设备验证令牌')
+    m_code = models.CharField(default='', max_length=64, verbose_name='手机唯一标识')
+    lang = models.CharField(default='en', max_length=8, verbose_name='推送语言')
+    tz = models.CharField(default='0', max_length=8, verbose_name='时区')
+    logout = models.BooleanField(default=False, verbose_name=u'退出登录')
+
+    class Meta:
+        db_table = 'gateway_push'
+        verbose_name = '网关推送'
+        verbose_name_plural = verbose_name
+        app_label = 'PushModel'
+
+
 # 设备通道配置
 class UidChannelSetModel(models.Model):
     id = models.AutoField(primary_key=True, verbose_name='自增id')
@@ -2538,7 +2558,8 @@ class GatewaySubDevice(models.Model):
     ieee_addr = models.CharField(default='', max_length=64, verbose_name=u'长地址')
     src_addr = models.CharField(default='', max_length=16, verbose_name=u'短地址')
     status = models.SmallIntegerField(default=0, verbose_name='状态')  # 0:关闭, 1:开启
-    is_tampered = models.SmallIntegerField(default=0, verbose_name='拆动状态')  # 0:正常, 1:被拆动
+    # 0:正常, 1:被拆动, 智能按钮紧急开关状态: 0:关闭, 1:开启
+    is_tampered = models.SmallIntegerField(default=0, verbose_name='拆动状态')
     mac = models.CharField(default='', max_length=32, verbose_name=u'mac地址')
     device_model = models.CharField(default='', max_length=16, verbose_name=u'设备型号')
     manufacturer = models.CharField(default='', max_length=16, verbose_name=u'制造商')
@@ -2603,16 +2624,69 @@ class SensorRecord(models.Model):
         app_label = 'PushModel'
 
 
+class SmartScene(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记id')
+    user = models.ForeignKey(Device_User, to_field='userID', default='', on_delete=models.CASCADE,
+                             verbose_name='关联用户表id')
+    device_id = models.CharField(default='', max_length=32, verbose_name=u'关联设备信息id')
+    sub_device_id = models.IntegerField(default=0, verbose_name=u'关联子设备表id')
+    scene_name = models.CharField(default='', max_length=100, verbose_name=u'场景名称')
+    conditions = models.TextField(default='', verbose_name=u'条件')
+    tasks = models.TextField(default='', verbose_name=u'任务')
+    is_all_day = models.SmallIntegerField(default=0, verbose_name=u'是否全天')  # 0: 不设置时间, 1: 全天, 2: 非全天
+    effective_time_id = models.IntegerField(default=0, verbose_name=u'关联场景执行时间id')
+    is_enable = models.BooleanField(default=True, verbose_name=u'是否开启')
+    device_data = models.TextField(default='', verbose_name=u'设备场景数据')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+
+    class Meta:
+        db_table = 'smart_scene'
+        verbose_name = '智能场景'
+        verbose_name_plural = verbose_name
+
+
+class EffectiveTime(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name=u'自增标记id')
+    start_time = models.SmallIntegerField(default=0, verbose_name=u'开始时间')
+    end_time = models.SmallIntegerField(default=0, verbose_name=u'结束时间')
+    repeat = models.SmallIntegerField(default=0, verbose_name=u'重复周期')
+
+    class Meta:
+        db_table = 'effective_time'
+        verbose_name = '场景执行时间'
+        verbose_name_plural = verbose_name
+
+
+class SceneLog(models.Model):
+    id = models.AutoField(primary_key=True, verbose_name='自增标记ID')
+    scene_id = models.IntegerField(default=0, verbose_name='关联场景id')
+    device_id = models.CharField(default='', max_length=32, verbose_name='关联网关id')
+    sub_device_id = models.IntegerField(default=0, verbose_name='关联子设备id')
+    scene_log = models.TextField(default='', verbose_name='场景日志')
+    status = models.SmallIntegerField(default=0, verbose_name='场景状态')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'scene_log'
+        verbose_name = '场景日志'
+        verbose_name_plural = verbose_name
+        app_label = 'PushModel'
+
+
 class UnicomCombo(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
     package_id = models.CharField(default='', max_length=32, verbose_name=u'联通套餐id')
     combo_name = models.CharField(default='', max_length=32, verbose_name=u'套餐名称')
     status = models.SmallIntegerField(default=0, verbose_name='状态{0:开启,1:停用}')
+    # 套餐类型 0:商用,1:初始化赠送
+    combo_type = models.SmallIntegerField(default=0, verbose_name='套餐类型')
     flow_total = models.IntegerField(default=0, blank=True, verbose_name=u'流量总量值 单位(MB)')
     expiration_days = models.IntegerField(default=0, blank=True, verbose_name=u'有效期天数')
     expiration_type = models.SmallIntegerField(default=0, verbose_name=u'有效期类型,0=天,1=月,2=年')
     pay_type = models.ManyToManyField(to='Pay_Type', verbose_name='付款类型', db_table='unicom_combo_pay_type')
     price = models.CharField(blank=True, max_length=32, verbose_name=u'价格')
+    is_unlimited = models.SmallIntegerField(default=0, verbose_name=u'是否无限流量,,0:有限流量,1:无限流量')
     sort = models.IntegerField(default=0, blank=True, verbose_name=u'排序,越小越靠前')
     remark = models.TextField(blank=True, default='', verbose_name=u'描述信息')
     updated_time = models.IntegerField(default=0, verbose_name='更新时间')
@@ -2629,12 +2703,16 @@ class UnicomCombo(models.Model):
 class UnicomComboOrderInfo(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
     iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
-    renew_list_id = models.CharField(default='', max_length=32, verbose_name=u'联通订购成功套餐队列id')
+    renew_list_id = models.CharField(blank=True, default='', max_length=32, verbose_name=u'联通订购成功套餐队列id')
     status = models.SmallIntegerField(default=0, verbose_name='状态{0:未使用,1:已使用,2:已过期}')
-    orders = models.ForeignKey(Order_Model, to_field='orderID', default='', on_delete=models.CASCADE,
-                               verbose_name='关联订单表')
+    order_id = models.CharField(blank=True, default='', max_length=32, verbose_name=u'关联订单表')
     combo = models.ForeignKey(UnicomCombo, to_field='id', default='', on_delete=models.CASCADE,
                               verbose_name=u'联通套餐表')
+    year = models.IntegerField(default=0, verbose_name='使用年')
+    month = models.IntegerField(default=0, verbose_name='使用月')
+    flow_total_usage = models.CharField(blank=True, default='', max_length=32, verbose_name=u'激活时当月已用流量')
+    sort = models.IntegerField(default=99, blank=True, verbose_name=u'排序')
+    next_month_activate = models.BooleanField(blank=True, default=False, verbose_name=u'下月激活')
     activation_time = models.IntegerField(default=0, verbose_name='激活时间')
     expire_time = models.IntegerField(default=0, verbose_name='过期时间')
     updated_time = models.IntegerField(default=0, verbose_name='更新时间')
@@ -2649,9 +2727,12 @@ class UnicomComboOrderInfo(models.Model):
 
 class UnicomDeviceInfo(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
-    iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    iccid = models.CharField(db_index=True, unique=True, max_length=32, verbose_name=u'完整的20位纯数字ICCID')
+    status = models.SmallIntegerField(default=0, verbose_name=u'状态{0:可测试,1:测试完成,2:已使用}')
     serial_no = models.CharField(default='', max_length=32, verbose_name=u'设备序列号')
     user_id = models.CharField(blank=True, max_length=32, verbose_name=u'用户id')
+    card_type = models.SmallIntegerField(default=0, verbose_name=u'状态{0:联通,1:电信,2:移动}')
+    main_card = models.SmallIntegerField(default=0, verbose_name=u'状态{0:主卡,1:拔插卡}')
     updated_time = models.IntegerField(default=0, verbose_name='更新时间')
     created_time = models.IntegerField(default=0, verbose_name='创建时间')
 
@@ -2665,7 +2746,7 @@ class UnicomDeviceQueueMonitoringPush(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
     iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
     serial_no = models.CharField(default='', max_length=32, verbose_name=u'序列号')
-    sign = models.CharField(default='', max_length=32, verbose_name=u'验证签名')
+    sign = models.CharField(default='', max_length=128, verbose_name=u'验证签名')
     time = models.CharField(default='', max_length=32, verbose_name=u'推送时间(yyyymmddhhmiss)')
     type = models.CharField(default='', max_length=32, verbose_name=u'推送类型:DEVICE_QUEUE_MONITORING:设队列监控;')
     current_renew_list_id = models.CharField(default='', max_length=32, verbose_name=u'队列ID')
@@ -2683,7 +2764,7 @@ class UnicomDeviceStatusChangePush(models.Model):
     id = models.AutoField(primary_key=True, verbose_name=u'自增标记Id')
     iccid = models.CharField(default='', max_length=32, verbose_name=u'完整的20位纯数字ICCID')
     serial_no = models.CharField(default='', max_length=32, verbose_name=u'序列号')
-    sign = models.CharField(default='', max_length=32, verbose_name=u'验证签名')
+    sign = models.CharField(default='', max_length=128, verbose_name=u'验证签名')
     time = models.CharField(default='', max_length=32, verbose_name=u'推送时间(yyyymmddhhmiss)')
     # 变更类型: DEVICE_REAL_NAME_STATUS_CHANGE:实名状态变更;DEVICE_STATUS_CHANGE:设备状态变更;
     type = models.CharField(default='', max_length=32, verbose_name=u'变更类型')
@@ -2699,3 +2780,38 @@ class UnicomDeviceStatusChangePush(models.Model):
         db_table = 'unicom_device_status_change_push'
         verbose_name = '联通设备状态变更推送表'
         verbose_name_plural = verbose_name
+
+
+class UnicomComboExperienceHistory(models.Model):
+    id = models.AutoField(primary_key=True)
+    # 0: 免费体验, 1: 激活码
+    experience_type = models.SmallIntegerField(default=0, verbose_name='体验类型')
+    iccid = models.CharField(max_length=32, default='', verbose_name='联通20位ICCID')
+    do_time = models.IntegerField(default=0, verbose_name='激活时间')
+
+    class Meta:
+        db_table = 'unicom_combo_experience_history'
+        verbose_name = '联通套餐体验历史表'
+        verbose_name_plural = verbose_name
+
+
+class UnicomFlowPush(models.Model):
+    id = models.AutoField(primary_key=True)
+    user_id = models.CharField(default='', max_length=32, verbose_name=u'用户id')
+    # 0: 剩余10%流量预警, 1: 流量到期
+    type = models.SmallIntegerField(default=0, verbose_name='流量推送类型')
+    combo_order_id = models.CharField(max_length=32, default='', verbose_name='当前订单套餐id')
+    serial_no = models.CharField(max_length=32, default='', verbose_name='序列号')
+    flow_total_usage = models.DecimalField(default=0, max_digits=10, decimal_places=2, verbose_name=u'当月实际流量用量 单位(MB)')
+    flow_total = models.DecimalField(default=0, max_digits=10, decimal_places=2, verbose_name=u'流量总量 单位(MB)')
+    status = models.SmallIntegerField(default=0, verbose_name=u'状态{0:待推送,1:已推送}')
+    updated_time = models.IntegerField(default=0, verbose_name='更新时间')
+    created_time = models.IntegerField(default=0, verbose_name='创建时间')
+
+    class Meta:
+        db_table = 'unicom_flow_push'
+        verbose_name = '联通流量用量推送'
+        verbose_name_plural = verbose_name
+        app_label = "PushModel"
+
+

+ 1 - 0
Object/LogsObject.py

@@ -124,6 +124,7 @@ class LogsObject(object):
             119: '二维码过期',
             120: '验证码过期',
             121: '验证码错了!',
+            172: '条件已存在',
             173: '数据不存在!',
             174: '数据已存在!',
             176: '删除错误',

+ 4 - 2
Object/ResponseObject.py

@@ -43,6 +43,7 @@ class ResponseObject(object):
             177: 'Update error',
             178: 'ADD error',
             179: 'Nickname repeated',
+            180: 'Smart button scene trigger conditions cannot be repeated',
             201: 'You can only add 3 custom voice at most',
             306: 'The link has expired!',
             309: 'Please ReLogin! errmsg token',
@@ -100,7 +101,7 @@ class ResponseObject(object):
             10041: 'This device has purchased a domestic cloud storage package, and cannot purchase a foreign cloud storage package',
             10042: 'The device has registered a certificate',
             10043: 'The device does not registered a certificate',
-            10044: 'Request to publish MQTT topic message failed',
+            10044: 'Failed to publish MQTT message',
             10045: 'Already the latest version',
             10046: 'Sorry, users who have activated cloud storage packages do not support logout at the moment, please contact customer service',
             10047: 'Please delete all devices under your account first',
@@ -150,6 +151,7 @@ class ResponseObject(object):
             177: '更新错误',
             178: '增加错误',
             179: '名称不能重复',
+            180: '智能按钮场景触发条件不能重复',
             201: '最多只能添加3条自定义语音',
             306: '链接已超过有效期!',
             309: '请重新登录!',
@@ -207,7 +209,7 @@ class ResponseObject(object):
             10041: '此设备已购买过国内云存套餐,无法购买国外云存套餐',
             10042: '此设备已注册证书',
             10043: '此设备没有注册证书',
-            10044: '请求发布MQTT主题消息失败',
+            10044: '发布MQTT消息失败',
             10045: '当前为最新版本',
             10046: '已开通云存的用户,暂不支持注销,请联系客服',
             10047: '请先删除您当前帐户下的所有设备',

+ 108 - 7
Object/UnicomObject.py

@@ -7,15 +7,17 @@
 @Software: PyCharm
 """
 import base64
+import datetime
 import json
+from decimal import Decimal
 
 import requests
 from Crypto.Cipher import AES
-from decimal import Decimal
-from Object.utils import SM3Util
 
 from Ansjer.config import unicomAppUrl, unicomAppId, unicomAppSecret, unicomTenantId, \
     unicomEncodeKey, unicomIvKey, unicomUserName, unicomPassword, unicomPushKey
+from Object.RedisObject import RedisObject
+from Object.utils import SM3Util
 from Object.utils.SymmetricCryptoUtil import AESencrypt
 
 """
@@ -216,8 +218,107 @@ class UnicomObjeect:
         headers['content-type'] = 'application/json'
         return requests.post(url, data=json.dumps(re_data), headers=headers)
 
+    @staticmethod
+    def get_text_dict(result):
+        """
+        响应结果转字典
+        @param result:
+        @return:
+        """
+        if result.status_code == 200:
+            return json.loads(result.text)
+        return None
+
+    @staticmethod
+    def unicom_flow_usage_cache(key, expire=0, **usage_data):
+        """
+        流量用量历史优先查询缓存
+        @param key: 缓存key
+        @param expire: 失效时间
+        @param usage_data: 查询参数
+        @return: 返回结果dict
+        """
+        redis = RedisObject()
+        usage_history = redis.get_data(key)
+        if usage_history:
+            usage_history = json.loads(usage_history)
+        else:
+            usage_history = UnicomObjeect().query_device_usage_history(**usage_data)
+            usage_history = UnicomObjeect().get_text_dict(usage_history)
+            redis.set_data(key=key, val=json.dumps(usage_history), expire=expire)
+        return usage_history
+
+    @staticmethod
+    def get_flow_usage_total(usage_year, usage_month, iccid):
+        """
+        查询当月用量历史
+        @param usage_year: 使用年
+        @param usage_month: 使用月
+        @param iccid: 联通id
+        @return: flow_total_usage 当月实际使用流量
+        """
+        flow_key = 'ASJ:UNICOM:FLOW:{}'
+        usage_data = {'iccid': iccid}
+        usage_history = UnicomObjeect().unicom_flow_usage_cache(flow_key.format(iccid), (60 * 10 + 3), **usage_data)
+        # 当月实际总使用流量
+        flow_total_usage = 0
+        if usage_history and usage_history['success']:
+            device_usage_history_list = usage_history['data']['deviceUsageHistory']
+            if device_usage_history_list:
+                for item in device_usage_history_list:
+                    if item['year'] != usage_year or item['month'] != usage_month:
+                        continue
+                    flow_total_usage += item['flowTotalUsage']
+        return flow_total_usage
+
+    @staticmethod
+    def change_device_to_activate(iccid):
+        """
+        根据iccid判断是否激活,未激活则修改为激活状态
+        @param iccid:
+        @return:
+        """
+        if iccid:
+            re_data = {'iccid': iccid}
+            result = UnicomObjeect().query_device_status(**re_data)
+            res_dict = UnicomObjeect().get_text_dict(result)
+            # 状态不等于1(激活)时进行激活 1:激活;2:停用
+            if res_dict['data']['status'] != 1:
+                re_data = {"iccid": iccid, "status": 1}
+                UnicomObjeect().update_device_state(**re_data)
+            return True
+        return None
+
+    @staticmethod
+    def change_device_to_disable(iccid):
+        """
+        修改设备为停用,并查看是否修改成功
+        @param iccid:
+        @return:
+        """
+        if iccid:
+            re_data = {"iccid": iccid, "status": 2}
+            UnicomObjeect().update_device_state(**re_data)
+            # 查询是否停用成功
+            re_data.pop('status')
+            result = UnicomObjeect().query_device_status(**re_data)
+            res_dict = UnicomObjeect().get_text_dict(result)
+            if res_dict['data']['status'] != 3:
+                UnicomObjeect().update_device_state(**re_data)
+            return True
+        return None
+
 
 if __name__ == '__main__':
+
+    today = datetime.datetime.today()
+    year = today.year
+    month = today.month
+    print(year)
+    print(month)
+    print(type(year))
+    if not '':
+        print('为空')
     price = '12.13'
     print(float(price))
     discount = '6'
@@ -229,10 +330,10 @@ if __name__ == '__main__':
     print(unicom_api.createSign(**data))
     # result = unicom_api.generate_token()
     # result = unicom_api.refresh_token('5d0c0f30-99bd-4f17-9614-3524495b05d4')
-    params = {'iccid': '89860620170009628001'}
-    response = unicom_api.verify_device(**params)
+    params = {'iccid': '89860621330065433774', 'status': 2}
+    # response = unicom_api.verify_device(**params)
     # response = unicom_api.query_device_status(**params)
-    # response = unicom_api.update_device_state(**params)
+    response = unicom_api.update_device_state(**params)
     # response = unicom_api.query_device_usage_history(**params)
     # response = unicom_api.query_current_renew_list_usage_details(**params)
     # unicom_api.get_device_batch_detail()
@@ -240,8 +341,8 @@ if __name__ == '__main__':
     # response = unicom_api.query_renewal_list(**params)
 
     if response.status_code == 200:
-        res_dict = json.loads(response.text)
-        print(res_dict)
+        res = json.loads(response.text)
+        print(res)
     response_json = {
         "success": True,
         "msg": "操作成功",

+ 159 - 2
Object/utils/LocalDateTimeUtil.py

@@ -7,9 +7,118 @@
 # @Email   : zhangdongming@asj6.wecom.work
 # @File    : LocalDateTimeUtil.py
 # @Software: PyCharm
+import calendar
 import datetime
 import time
 
+from dateutil.relativedelta import relativedelta
+
+
+def get_cur_month():
+    # 获取当前月
+    return datetime.datetime.now().strftime("%Y-%m")
+
+
+def get_last_month_num(number=1):
+    # 获取前几个月
+    month_date = datetime.datetime.now().date() - relativedelta(months=number)
+    return month_date.strftime("%Y-%m")
+
+
+def get_next_month(number=1):
+    # 获取后几个月
+    month_date = datetime.datetime.now().date() + relativedelta(months=number)
+    return month_date.strftime("%Y-%m")
+
+
+def get_cur_month_start():
+    # 获取当前月的第一天
+    month_str = datetime.datetime.now().strftime('%Y-%m')
+    return '{}-01'.format(month_str)
+
+
+def get_cur_month_end():
+    # 获取当前月的最后一天
+    """
+    param: month_str 月份,2021-04
+    """
+    # return: 格式 %Y-%m-%d
+
+    month_str = datetime.datetime.now().strftime('%Y-%m')
+    year, month = int(month_str.split('-')[0]), int(month_str.split('-')[1])
+    end = calendar.monthrange(year, month)[1]
+    return '{}-{}-{}'.format(year, month, end)
+
+
+def get_last_month_start(month_str=None):
+    # 获取上一个月的第一天
+    """
+    param: month_str 月份,2021-04
+    """
+    # return: 格式 %Y-%m-%d
+    if not month_str:
+        month_str = datetime.datetime.now().strftime('%Y-%m')
+    year, month = int(month_str.split('-')[0]), int(month_str.split('-')[1])
+    if month == 1:
+        year -= 1
+        month = 12
+    else:
+        month -= 1
+    return '{}-{}-01'.format(year, month)
+
+
+def get_next_month_start(month_str=None):
+    # 获取下一个月的第一天
+    """
+    param: month_str 月份,2021-04
+    """
+    # return: 格式 %Y-%m-%d
+    if not month_str:
+        month_str = datetime.datetime.now().strftime('%Y-%m')
+    year, month = int(month_str.split('-')[0]), int(month_str.split('-')[1])
+    if month == 12:
+        year += 1
+        month = 1
+    else:
+        month += 1
+    return '{}-{}-01'.format(year, month)
+
+
+def get_last_month_end(month_str=None):
+    # 获取上一个月的最后一天
+    """
+    param: month_str 月份,2021-04
+    """
+    # return: 格式 %Y-%m-%d
+    if not month_str:
+        month_str = datetime.datetime.now().strftime('%Y-%m')
+    year, month = int(month_str.split('-')[0]), int(month_str.split('-')[1])
+    if month == 1:
+        year -= 1
+        month = 12
+    else:
+        month -= 1
+    end = calendar.monthrange(year, month)[1]
+    return '{}-{}-{}'.format(year, month, end)
+
+
+def get_next_month_end(month_str=None):
+    # 获取下一个月的最后一天
+    """
+    param: month_str 月份,2021-04
+    """
+    # return: 格式 %Y-%m-%d
+    if not month_str:
+        month_str = datetime.datetime.now().strftime('%Y-%m')
+    year, month = int(month_str.split('-')[0]), int(month_str.split('-')[1])
+    if month == 12:
+        year += 1
+        month = 1
+    else:
+        month += 1
+    end = calendar.monthrange(year, month)[1]
+    return '{}-{}-{}'.format(year, month, end)
+
 
 def get_last_first_date_and_last_date(n):
     """
@@ -71,6 +180,21 @@ def get_before_days_timestamp(timestamp, days=1):
     return 0
 
 
+def get_after_days_timestamp(timestamp, days=1):
+    """
+    获取之后日期时间戳-秒级
+    @param timestamp: 时间戳
+    @param days: 天数
+    @return: (timestamp + second * hour * days) 时间戳
+    """
+    if days:
+        second = 3600
+        hour = 24
+        if days > 0:
+            return timestamp + second * hour * days
+    return 0
+
+
 def date_to_week(str_date):
     """
     日期获取星期几
@@ -110,10 +234,43 @@ def get_start_and_end_time(date, str_format):
     return 0
 
 
-if __name__ == "__main__":
+if __name__ == '__main__':
+    zero_today, last_today = get_today_date(True)
+    month_end = get_cur_month_end()
+    start_time, month_end_time = get_start_and_end_time(month_end, '%Y-%m-%d')
+    print(zero_today)
+    print(month_end_time)
+
+
+    # # 获取当前月
+    # print('当前月', get_cur_month())
+    # # 获取上一个月
+    # print('上一个月', get_last_month_num())
+    # # 获取上两个月
+    # print('上两个月', get_last_month_num(number=2))
+    # # 获取下一个月
+    # print('下一个月', get_next_month())
+    # # 获取下两个月
+    # print('下两个月', get_next_month(number=2))
+    # # 获取当前月的第一天
+    # print('当前月的第一天', get_cur_month_start())
+    # # 获取当前月的最后一天
+    # print('当前月的最后一天', get_cur_month_end())
+    # # 获取上个月的第一天
+    # print('上个月的第一天', get_last_month_start())
+    # # 获取下个月的第一天
+    # print('下个月的第一天', get_next_month_start())
+    # # 获取上个月的最后一天
+    # print('上个月的最后一天', get_last_month_end())
+    # # 获取下个月的最后一天
+    # print('下个月的最后一天', get_next_month_end())
     dd = str(1650791368303)
     print(dd[0:10])
     print(dd[10:])
     dateArray = datetime.datetime.utcfromtimestamp(1650791368)
     print(dateArray.date())
-    print(get_start_and_end_time('20220317', '%Y%m%d'))
+    next_start_time, next_end_time = get_start_and_end_time(get_next_month_start(), '%Y-%m-%d')
+    print(type(next_end_time))
+    print('下月开始时间{}'.format(next_start_time))
+    start_time, end_time = get_start_and_end_time(get_next_month_end(), '%Y-%m-%d')
+    print('下月结束时间{}'.format(end_time))

+ 80 - 0
Object/utils/PayUtil.py

@@ -0,0 +1,80 @@
+# -*- encoding: utf-8 -*-
+"""
+@File    : PayUtil.py
+@Time    : 2022/6/29 11:41
+@Author  : stephen
+@Email   : zhangdongming@asj6.wecom.work
+@Software: PyCharm
+"""
+from urllib.parse import quote
+
+from Ansjer.config import SERVER_DOMAIN_SSL
+from Object.AliPayObject import AliPayObject
+from Object.WechatPayObject import WechatPayObject
+
+"""
+支付服务
+"""
+
+
+class PayService:
+
+    @staticmethod
+    def create_alipay_payment(passback_params, order_id, price, title, notify_url, content, response):
+        """
+        创建支付宝支付
+        @param passback_params: 携带参数支付宝回调原样返回
+        @param order_id: 订单编号
+        @param price: 价格
+        @param title: 标题
+        @param notify_url: 异步回调通知URL
+        @param content: 内容
+        @param response: 响应结果
+        @return: 网站支付链接
+        """
+        aliPayObj = AliPayObject()
+        alipay = aliPayObj.conf()
+        subject = title + content
+        order_string = alipay.api_alipay_trade_wap_pay(
+            out_trade_no=order_id,
+            total_amount=price,
+            subject=subject,
+            return_url="{}web/paid2/success.html".format(SERVER_DOMAIN_SSL),
+            notify_url="{}{}".format(SERVER_DOMAIN_SSL, notify_url),
+            quit_url="{}web/paid2/fail.html".format(SERVER_DOMAIN_SSL),
+            passback_params=quote(passback_params)
+        )
+        if not order_string:
+            return response.json(10, '生成订单错误.')
+        return aliPayObj.alipay_prefix + order_string
+
+    @staticmethod
+    def create_wechat_payment(attach, order_id, price, ip, notify_url, content, response):
+        """
+        创建微信支付
+        @param attach: 参数微信回调通知原样返回
+        @param order_id: 订单编号
+        @param price: 价格
+        @param ip: 用户支付ip地址
+        @param notify_url: 异步通知回调URL
+        @param content: 内容
+        @param response: 响应结果
+        @return: 网站支付链接
+        """
+        notify_url = "{}{}".format(SERVER_DOMAIN_SSL, notify_url)
+        pay = WechatPayObject()
+        # 统一调用接口
+        pay.get_parameter(order_id, content, float(price) * 100, ip, notify_url, quote(attach))
+        sign_params = pay.re_finall(orderid=order_id)
+        if not sign_params:
+            return response.json(10, '生成订单错误.')
+        return sign_params
+
+    @staticmethod
+    def get_two_float(f_str, n):
+        # f_str = '{}'.format(f_str) 也可以转换为字符串
+        f_str = str(f_str)
+        a, b, c = f_str.partition('.')
+        # 如论传入的函数有几位小数,在字符串后面都添加n为小数0
+        c = (c + "0" * n)[:n]
+        return ".".join([a, c])

+ 19 - 1
Service/CommonService.py

@@ -18,6 +18,8 @@ from pyipip import IPIPDatabase
 from Ansjer.config import BASE_DIR, SERVER_DOMAIN_SSL, CONFIG_INFO, CONFIG_TEST, CONFIG_CN
 from Controller.CheckUserData import RandomStr
 from Model.models import iotdeviceInfoModel, Device_Info, CountryModel, RegionModel, UIDModel
+from Object.ResponseObject import ResponseObject
+from Object.TokenObject import TokenObject
 
 
 class CommonService:
@@ -483,7 +485,7 @@ class CommonService:
         @param msg: 消息内容
         @return: boolean
         """
-        if not all([thing_name, topic_name, msg]):
+        if not all([thing_name, topic_name]):
             return False
 
         try:
@@ -635,3 +637,19 @@ GCqvlyw5dfxNA+EtxNE2wCW/LW7ENJlACgcfgPlBZtpLheWoZB/maw4=
                 region_qs = RegionModel.objects.filter(continent_code='NA').values("id")
                 region_id = region_qs[0]['id']
         return region_id
+
+    @staticmethod
+    def verify_token_get_user_id(request_dict, request):
+        """
+        认证token,获取user id
+        @param request_dict: 请求参数
+        @param request: 请求体
+        @return: token_obj.code, token_obj.userID, response
+        """
+        try:
+            token_obj = TokenObject(request.META.get('HTTP_AUTHORIZATION'))
+            lang = request_dict.get('lang', None)
+            response = ResponseObject(lang if lang else token_obj.lang)
+            return token_obj.code, token_obj.userID, response
+        except Exception as e:
+            print(e)

+ 3 - 3
Service/EquipmentInfoService.py

@@ -269,9 +269,9 @@ class EquipmentInfoService:
         comb_ai_event_type = []
         for i in range(1, len(type) + 1):  # 计算所有组合,如[1, 2, 3, 4], 4取1,4取2,4取3,4取4
             for s in itertools.combinations(type, i):
-                    s_list = list(s)
-                    s_list = [str(v) for v in s_list]
-                    comb_ai_event_type.append(s_list)
+                s_list = list(s)
+                s_list = [str(v) for v in s_list]
+                comb_ai_event_type.append(s_list)
         regroup_list = []
         for val in comb_ai_event_type:  # 组合ai类型组合,如[[2,3],[1,3]] -> [23, 13]
             val = ''.join(val)