diff --git a/apps/hrm/serializers.py b/apps/hrm/serializers.py index 930036b6..49f97ef8 100755 --- a/apps/hrm/serializers.py +++ b/apps/hrm/serializers.py @@ -17,14 +17,25 @@ from rest_framework.exceptions import ParseError from django.conf import settings +class EmployeeShortSerializer(CustomModelSerializer): + belong_dept_name = serializers.CharField( + source='belong_dept.name', read_only=True) + + class Meta: + model = Employee + fields = ['id', 'name', 'belong_dept_name', 'user', 'third_info'] + + class EmployeeSimpleSerializer(CustomModelSerializer): - belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) + belong_dept_name = serializers.CharField( + source='belong_dept.name', read_only=True) post_name = serializers.CharField(source='post.name', read_only=True) location = serializers.SerializerMethodField() class Meta: model = Employee - fields = ['id', 'type', 'name', 'belong_dept', 'belong_dept_name', 'post', 'post_name', 'photo', 'third_info', 'number', 'id_number', 'location'] + fields = ['id', 'type', 'name', 'belong_dept', 'belong_dept_name', 'post', + 'post_name', 'photo', 'third_info', 'number', 'id_number', 'location'] def get_location(self, obj): key_str = 'ep_{}'.format(obj.id) @@ -40,7 +51,8 @@ class EmployeeSimpleSerializer(CustomModelSerializer): class EmployeeCreateUpdateSerializer(CustomModelSerializer): - id_number = serializers.CharField(label="身份证号", validators=[check_id_number_e]) + id_number = serializers.CharField( + label="身份证号", validators=[check_id_number_e]) class Meta: model = Employee @@ -72,7 +84,8 @@ class EmployeeCreateUpdateSerializer(CustomModelSerializer): instance = super().update(instance, validated_data) if old_photo != instance.photo: # 如果照片有变动,需要更新人脸库 # 使用的是face_recongition - face_data, msg = HrmService.get_facedata_from_img_x(settings.BASE_DIR + instance.photo) + face_data, msg = HrmService.get_facedata_from_img_x( + settings.BASE_DIR + instance.photo) in_face_data = instance.face_data if face_data: if isinstance(in_face_data, dict): @@ -104,17 +117,19 @@ class EmployeeCreateUpdateSerializer(CustomModelSerializer): if instance.type in ['employee', 'remployee']: start_time = None end_time = None - if instance.third_info.get('dh_face_card', None) is None and instance.type == 'employee': # 如果是正式员工,给长时间期限 + # 如果是正式员工,给长时间期限 + if instance.third_info.get('dh_face_card', None) is None and instance.type == 'employee': start_time = now end_time = now + timedelta(days=7300) if instance.job_state in [20, 30] and old_job_state == 10: # 离职或退休 start_time = now end_time = now + timedelta(hours=8) - elif instance.job_state == 10 and old_job_state in [20, 30] and instance.type == 'employee': # 正式员工重新在职 + # 正式员工重新在职 + elif instance.job_state == 10 and old_job_state in [20, 30] and instance.type == 'employee': start_time = now end_time = now + timedelta(days=7300) HrmService.sync_dahua_employee(ep=instance, old_photo=old_photo, - start_time=start_time, end_time=end_time) + start_time=start_time, end_time=end_time) return instance @@ -124,7 +139,8 @@ class EmployeeImproveSerializer(CustomModelSerializer): class Meta: model = Employee - fields = ['photo', 'id_number', 'email', 'gender', 'signature', 'photo_f', 'signature_f', 'phone'] + fields = ['photo', 'id_number', 'email', 'gender', + 'signature', 'photo_f', 'signature_f', 'phone'] extra_kwargs = { 'number': {'required': True}, 'photo': {'required': True}, @@ -147,7 +163,8 @@ class ChannelAuthoritySerializer(serializers.Serializer): class EmployeeSerializer(CustomModelSerializer): belong_dept_ = DeptSimpleSerializer(source='belong_dept', read_only=True) user_ = UserSimpleSerializer(source='user', read_only=True) - belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) + belong_dept_name = serializers.CharField( + source='belong_dept.name', read_only=True) post_name = serializers.CharField(source='post.name', read_only=True) blt_ = serializers.SerializerMethodField() photo_f = MyFilePathField(source='photo', read_only=True) @@ -161,7 +178,7 @@ class EmployeeSerializer(CustomModelSerializer): def get_blt_(self, obj): if hasattr(obj, 'blt'): from apps.third.serializers import TDeviceSimpleSerializer - return TDeviceSimpleSerializer(instance=obj.blt).data + return TDeviceSimpleSerializer(instance=obj.blt).data # if hasattr(obj, 'tdevice'): # from apps.third.serializers import TDeviceSimpleSerializer # return TDeviceSimpleSerializer(instance=obj.tdevice).data @@ -197,6 +214,7 @@ class ClockRecordListSerializer(serializers.ModelSerializer): model = ClockRecord fields = '__all__' + class ClockRecordSimpleSerializer(serializers.ModelSerializer): class Meta: model = ClockRecord @@ -218,7 +236,8 @@ class CertificateCreateUpdateSerializer(CustomModelSerializer): class CertificateSerializer(CustomModelSerializer): - employee_name = serializers.CharField(source='employee.name', read_only=True) + employee_name = serializers.CharField( + source='employee.name', read_only=True) file_f = MyFilePathField(source='file', read_only=True) class Meta: @@ -228,4 +247,4 @@ class CertificateSerializer(CustomModelSerializer): class CorrectSerializer(serializers.Serializer): start_time = serializers.DateTimeField() - end_time = serializers.DateTimeField() \ No newline at end of file + end_time = serializers.DateTimeField() diff --git a/apps/hrm/services.py b/apps/hrm/services.py index 4dde5139..432302b9 100755 --- a/apps/hrm/services.py +++ b/apps/hrm/services.py @@ -34,7 +34,7 @@ class HrmService: Returns: _type_: _description_ """ - if not settings.DAHUA_ENABLED: # 如果大华没启用, 直接返回 + if not settings.DAHUA_ENABLED: # 如果大华没启用, 直接返回 return dh_id = ep.third_info.get('dh_id', None) dh_photo = ep.third_info.get('dh_photo', None) @@ -68,7 +68,8 @@ class HrmService: }] } if ep.photo != old_photo and ep.photo: - _, res = dhClient.request(**dhapis['person_img_upload'], file_path_rela=ep.photo) + _, res = dhClient.request( + **dhapis['person_img_upload'], file_path_rela=ep.photo) dh_photo = res["fileUrl"] json_data.update( { @@ -98,7 +99,8 @@ class HrmService: "email": ep.email, "sex": 1 if ep.gender == '男' else 2 } - _, res = dhClient.request(**dhapis['person_img_upload'], file_path_rela=ep.photo) + _, res = dhClient.request( + **dhapis['person_img_upload'], file_path_rela=ep.photo) dh_photo = res["fileUrl"] json_data.update( { @@ -129,16 +131,20 @@ class HrmService: if start_time is None: # 如果时间段未提供,跳过更新操作 pass else: - startDate = timezone.localtime(start_time).strftime("%Y-%m-%d %H:%M:%S") - endDate = timezone.localtime(end_time).strftime("%Y-%m-%d %H:%M:%S") + startDate = timezone.localtime( + start_time).strftime("%Y-%m-%d %H:%M:%S") + endDate = timezone.localtime( + end_time).strftime("%Y-%m-%d %H:%M:%S") json_data = { "cardNumber": cardNumber, "startDate": startDate, "endDate": endDate, "departmentId": departmentId, } - _, res = dhClient.request(**dhapis['card_update'], json=json_data) - cls.save(ep, data={'dh_face_card_start': startDate, 'dh_face_card_end': endDate}) + _, res = dhClient.request( + **dhapis['card_update'], json=json_data) + cls.save( + ep, data={'dh_face_card_start': startDate, 'dh_face_card_end': endDate}) return cardNumber else: _, res = dhClient.request(**dhapis['card_gen_id']) @@ -147,10 +153,13 @@ class HrmService: if start_time is None: # 如果未规定时间范围, 默认1小时 now = datetime.now() startDate = now.strftime("%Y-%m-%d %H:%M:%S") - endDate = (now+timedelta(minutes=60)).strftime("%Y-%m-%d %H:%M:%S") + endDate = (now+timedelta(minutes=60) + ).strftime("%Y-%m-%d %H:%M:%S") else: - startDate = timezone.localtime(start_time).strftime("%Y-%m-%d %H:%M:%S") - endDate = timezone.localtime(end_time).strftime("%Y-%m-%d %H:%M:%S") + startDate = timezone.localtime( + start_time).strftime("%Y-%m-%d %H:%M:%S") + endDate = timezone.localtime( + end_time).strftime("%Y-%m-%d %H:%M:%S") json_data = { "id": cardId, "cardNumber": cardNumber, @@ -180,7 +189,9 @@ class HrmService: from apps.third.models import TDevice dh_face_card = ep.third_info.get('dh_face_card', None) if dh_dchannels: - pass + # 只分配系统里有的 + dh_dchannels = list(TDevice.objects.filter( + code__in=dh_dchannels).values_list('code', flat=True)) else: # 查找可授予的门禁通道号 dh_dchannels = list(TDevice.objects.filter(type=TDevice.DEVICE_DCHANNEL, @@ -201,7 +212,8 @@ class HrmService: while ind < 8: time.sleep(6) try: - dhClient.request(**dhapis['card_door_authority'], json=json_data) + dhClient.request( + **dhapis['card_door_authority'], json=json_data) break except Exception as e: ind = ind + 1 @@ -220,6 +232,13 @@ class HrmService: # elif is_ok == 'error': # raise APIException(**DH_REQUEST_ERROR) cls.save(ep, data={'dh_dchannels': dh_dchannels}) + from apps.third.models import DoorAuth + DoorAuth.objects.filter(employee=ep).delete() + drs = [] + for i in dh_dchannels: + drs.append( + DoorAuth(employee=ep, dchannel=TDevice.objects.get(code=i))) + DoorAuth.objects.bulk_create(drs) return dh_dchannels @classmethod @@ -243,10 +262,11 @@ class HrmService: nodeCode = data['info']['extend']['acsChannelCode'] swip_time = data['info']['extend']['swingTime'] e_type = data['info']['extend']['enterOrExit'] - cls.swipe_next(nodeCode, id_number, swip_time, e_type, data['info']['extend']) - + cls.swipe_next(nodeCode, id_number, swip_time, + e_type, data['info']['extend']) + @classmethod - def swipe_offline(cls, data:dict): + def swipe_offline(cls, data: dict): """离线刷卡推送记录处理 """ for i in data['infoArray']: @@ -256,9 +276,9 @@ class HrmService: swip_time = i['swingTime'] e_type = i['enterOrExit'] cls.swipe_next(nodeCode, id_number, swip_time, e_type, i) - + @classmethod - def swipe_next(cls, nodeCode: str, id_number: str, swip_time: str, e_type:int, detail:dict): + def swipe_next(cls, nodeCode: str, id_number: str, swip_time: str, e_type: int, detail: dict): from apps.rpm.models import Rpj from apps.vm.models import Visit @@ -267,15 +287,17 @@ class HrmService: state=Visit.V_WORKING) Rpj.objects.filter(state=Rpj.RPJ_ENTER, remployees__employee__id_number=id_number).update( state=Rpj.RPJ_WORKING) - + # 打卡处理 device = TDevice.objects.filter(code=nodeCode).first() - ep = Employee.objects.filter(id_number=id_number, type__in=["employee", "remployee"]).first() + ep = Employee.objects.filter(id_number=id_number, type__in=[ + "employee", "remployee"]).first() if device and device.is_clock and ep: tzinfo = tz.gettz('Asia/Shanghai') - s_time_f = datetime.strptime(swip_time, "%Y-%m-%d %H:%M:%S").replace(tzinfo=tzinfo) + s_time_f = datetime.strptime( + swip_time, "%Y-%m-%d %H:%M:%S").replace(tzinfo=tzinfo) first_time = datetime(year=s_time_f.year, month=s_time_f.month, day=s_time_f.day, - hour=0, minute=0, second=0, tzinfo=tzinfo) + hour=0, minute=0, second=0, tzinfo=tzinfo) end_time = datetime(year=s_time_f.year, month=s_time_f.month, day=s_time_f.day, hour=23, minute=59, second=59, tzinfo=tzinfo) @@ -288,13 +310,13 @@ class HrmService: card_type = 20 elif e_type == 3: time_10_x = datetime(year=s_time_f.year, month=s_time_f.month, - day=s_time_f.day, hour=7, minute=20, second=0, tzinfo=tzinfo) + day=s_time_f.day, hour=7, minute=20, second=0, tzinfo=tzinfo) time_10_y = datetime(year=s_time_f.year, month=s_time_f.month, - day=s_time_f.day, hour=11, minute=0, second=0, tzinfo=tzinfo) + day=s_time_f.day, hour=11, minute=0, second=0, tzinfo=tzinfo) time_20_x = datetime(year=s_time_f.year, month=s_time_f.month, - day=s_time_f.day, hour=16, minute=0, second=0, tzinfo=tzinfo) + day=s_time_f.day, hour=16, minute=0, second=0, tzinfo=tzinfo) time_20_y = datetime(year=s_time_f.year, month=s_time_f.month, - day=s_time_f.day, hour=18, minute=10, second=0, tzinfo=tzinfo) + day=s_time_f.day, hour=18, minute=10, second=0, tzinfo=tzinfo) if time_10_x < s_time_f < time_10_y: card_type = 10 elif time_20_x < s_time_f < time_20_y: @@ -302,9 +324,10 @@ class HrmService: if card_type == 30: note = '非打卡时间范围' trigger = 'panel' - + # 先直接创建记录 - cr = ClockRecord.objects.filter(employee=ep, create_time=s_time_f).first() + cr = ClockRecord.objects.filter( + employee=ep, create_time=s_time_f).first() if cr: pass else: @@ -312,7 +335,7 @@ class HrmService: cr.employee = ep cr.create_time = s_time_f cr.type = card_type - cr.exception_type = None + cr.exception_type = None cr.trigger = trigger cr.detail = detail cr.note = note @@ -323,34 +346,38 @@ class HrmService: cr_10_q = ClockRecord.objects.filter( type=10, employee=ep, create_time__gte=first_time, create_time__lte=end_time) first_obj = cr_10_q.order_by('create_time').first() - cr_10_q.exclude(id=first_obj.id).update(type=30, exception_type=None) + cr_10_q.exclude(id=first_obj.id).update( + type=30, exception_type=None) elif card_type == 20: # 查找当天的出门记录 cr_20_q = ClockRecord.objects.filter( type=20, employee=ep, create_time__gte=first_time, create_time__lte=end_time) last_obj = cr_20_q.order_by('-create_time').first() - cr_20_q.exclude(id=last_obj.id).update(type=30, exception_type=None) + cr_20_q.exclude(id=last_obj.id).update( + type=30, exception_type=None) # 判断是否有异常 # 找到最近的上下打卡时间不一定是当天的 - cr_e = ClockRecord.objects.filter(create_time__lt=last_obj.create_time, employee=ep, type__in=[10, 20]).order_by('-create_time').first() + cr_e = ClockRecord.objects.filter(create_time__lt=last_obj.create_time, employee=ep, type__in=[ + 10, 20]).order_by('-create_time').first() if cr_e and last_obj: time_d = last_obj.create_time - cr_e.create_time if cr_e.type == 10: - if time_d < timedelta(hours=7): + if time_d < timedelta(hours=7): last_obj.exception_type = ClockRecord.E_TYPE_LESS last_obj.save() - elif time_d > timedelta(hours=14): + elif time_d > timedelta(hours=14): last_obj.exception_type = ClockRecord.E_TYPE_MORE last_obj.save() - elif time_d > timedelta(hours=10): + elif time_d > timedelta(hours=10): last_obj.exception_type = ClockRecord.E_TYPE_ADD last_obj.save() elif cr_e.type == 20: - last_obj.exception_type = ClockRecord.E_TYPE_MISS - last_obj.save() + last_obj.exception_type = ClockRecord.E_TYPE_MISS + last_obj.save() # 记录在岗情况 - last_obj_t = ClockRecord.objects.filter(employee=ep, type__in=[10,20]).order_by('-create_time').first() + last_obj_t = ClockRecord.objects.filter( + employee=ep, type__in=[10, 20]).order_by('-create_time').first() if last_obj_t: update_fields = {'last_check_time': last_obj_t.create_time} if last_obj_t.type == 10: @@ -358,48 +385,48 @@ class HrmService: else: update_fields['is_atwork'] = False Employee.objects.filter(id=ep.id).update(**update_fields) - - - # 此处可触发安全帽事件逻辑 - @classmethod def get_facedata_from_img_x(cls, img_path): import face_recognition try: picture_of_me = face_recognition.load_image_file(img_path) - my_face_encoding = face_recognition.face_encodings(picture_of_me, num_jitters=2)[0] + my_face_encoding = face_recognition.face_encodings( + picture_of_me, num_jitters=2)[0] face_data_list = my_face_encoding.tolist() return face_data_list, '' except: return None, '人脸数据获取失败请重新上传图片' - + @classmethod def face_compare_from_base64(cls, base64_data): import face_recognition filename = str(uuid.uuid4()) - filepath = settings.BASE_DIR +'/temp/face_' + filename +'.png' + filepath = settings.BASE_DIR + '/temp/face_' + filename + '.png' with open(filepath, 'wb') as f: f.write(base64_data) try: unknown_picture = face_recognition.load_image_file(filepath) - unknown_face_encoding = face_recognition.face_encodings(unknown_picture, num_jitters=2)[0] + unknown_face_encoding = face_recognition.face_encodings( + unknown_picture, num_jitters=2)[0] os.remove(filepath) except: os.remove(filepath) return None, '识别失败,请调整位置' # 匹配人脸库 - face_datas = cache.get('face_datas_dlib', None) # 使用的是face_datas_dlib作为key的 + # 使用的是face_datas_dlib作为key的 + face_datas = cache.get('face_datas_dlib', None) if face_datas is None: from apps.hrm.tasks import update_all_facedata_cache update_all_facedata_cache() face_datas = cache.get('face_datas_dlib') - results = face_recognition.compare_faces(face_datas['datas'], - unknown_face_encoding, tolerance=0.45) - face_distances = face_recognition.face_distance(face_datas['datas'], unknown_face_encoding) + results = face_recognition.compare_faces(face_datas['datas'], + unknown_face_encoding, tolerance=0.45) + face_distances = face_recognition.face_distance( + face_datas['datas'], unknown_face_encoding) best_match_index = np.argmin(face_distances) if results[best_match_index]: epId = face_datas['eps'][best_match_index] @@ -408,7 +435,7 @@ class HrmService: # first_match_index = results.index(True) # # 识别成功 # ep = Employee.objects.get(id=face_datas['eps'][first_match_index]) - # return ep, '' + # return ep, '' return None, '人脸未匹配,请调整位置' @classmethod @@ -416,7 +443,7 @@ class HrmService: from apps.utils.face import face_find # from deepface import DeepFace img_name = str(uuid.uuid4()) - img_path = settings.BASE_DIR +'/temp/face_' + img_name +'.jpg' + img_path = settings.BASE_DIR + '/temp/face_' + img_name + '.jpg' with open(img_path, 'wb') as f: f.write(base64_data) # db_path = os.path.join(settings.BASE_DIR, 'media/face') @@ -443,7 +470,8 @@ class HrmService: def get_facedata_from_img(cls, img_path): try: from deepface import DeepFace - embedding_objs = DeepFace.represent(img_path=img_path, model_name='Facenet') + embedding_objs = DeepFace.represent( + img_path=img_path, model_name='Facenet') return embedding_objs[0]["embedding"], '' except Exception as e: - return None, '人脸数据获取失败请重新上传图片' \ No newline at end of file + return None, '人脸数据获取失败请重新上传图片' diff --git a/apps/third/migrations/0009_doorauth.py b/apps/third/migrations/0009_doorauth.py new file mode 100644 index 00000000..2789281e --- /dev/null +++ b/apps/third/migrations/0009_doorauth.py @@ -0,0 +1,30 @@ +# Generated by Django 3.2.12 on 2023-10-09 02:54 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('hrm', '0015_clockrecord_note'), + ('third', '0008_alter_tdevice_employee'), + ] + + operations = [ + migrations.CreateModel( + name='DoorAuth', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('dchannel', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='third.tdevice', verbose_name='关联门通道')), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hrm.employee', verbose_name='关联用户')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/third/models.py b/apps/third/models.py index 24f04c11..12824329 100755 --- a/apps/third/models.py +++ b/apps/third/models.py @@ -31,7 +31,8 @@ class TDevice(BaseModel): (DEVICE_PANEL, '面板机') ) type = models.PositiveSmallIntegerField('设备类型', choices=DEVICE_CHOICE) - code = models.CharField('设备唯一标识', max_length=50, db_index=True, unique=True) + code = models.CharField('设备唯一标识', max_length=50, + db_index=True, unique=True) name = models.CharField('名称', max_length=50, null=True, blank=True) location = models.JSONField('位置信息', default=dict, null=False, blank=True) @@ -39,13 +40,15 @@ class TDevice(BaseModel): verbose_name='所在区', null=True, blank=True) areas = models.ManyToManyField(Area, verbose_name='覆盖区', related_name='tareas', blank=True) - obj_cate = models.CharField('绑定对象', max_length=20, help_text='people/...', null=True, blank=True) + obj_cate = models.CharField( + '绑定对象', max_length=20, help_text='people/...', null=True, blank=True) employee = models.OneToOneField(Employee, verbose_name='当前绑定人员', on_delete=models.SET_NULL, null=True, blank=True, related_name='blt') is_clock = models.BooleanField('是否打卡设备', default=False) access_list = models.JSONField('自动下发人员类型', default=list, null=False, blank=True, help_text='employee/remployee/visitor/driver') - mtask_uid = models.CharField('监控任务ID', max_length=100, null=True, blank=True) # 废弃字段 + mtask_uid = models.CharField( + '监控任务ID', max_length=100, null=True, blank=True) # 废弃字段 # algos = models.ManyToManyField('ecm.eventcate', through='ecm.algochannel', blank=True) third_info = models.JSONField('三方信息', default=dict, null=False, blank=True) @@ -62,9 +65,12 @@ class BltBind(BaseModel): ) type = models.PositiveSmallIntegerField('绑定类型', default=10, help_text='10(绑定)/20(解绑)', choices=BIND_TYPE_CHOICES) - obj_cate = models.CharField('绑定对象', max_length=20, help_text='people/...', null=True, blank=True) - blt = models.ForeignKey(TDevice, verbose_name='关联标签', on_delete=models.CASCADE) - employee = models.ForeignKey(Employee, verbose_name='关联人员', on_delete=models.CASCADE, null=True, blank=True) + obj_cate = models.CharField( + '绑定对象', max_length=20, help_text='people/...', null=True, blank=True) + blt = models.ForeignKey(TDevice, verbose_name='关联标签', + on_delete=models.CASCADE) + employee = models.ForeignKey( + Employee, verbose_name='关联人员', on_delete=models.CASCADE, null=True, blank=True) class Tlog(BaseModel): @@ -83,3 +89,10 @@ class Tlog(BaseModel): errors = models.TextField(null=True, blank=True) params = models.JSONField(null=True, blank=True) body = models.JSONField(null=True, blank=True) + + +class DoorAuth(BaseModel): + employee = models.ForeignKey( + Employee, verbose_name='关联用户', on_delete=models.CASCADE) + dchannel = models.ForeignKey( + TDevice, verbose_name='关联门通道', on_delete=models.CASCADE) diff --git a/apps/third/serializers.py b/apps/third/serializers.py index 5b32c91a..f27b8d2c 100755 --- a/apps/third/serializers.py +++ b/apps/third/serializers.py @@ -1,8 +1,8 @@ from rest_framework import serializers from apps.am.models import Area -from apps.hrm.serializers import EmployeeSimpleSerializer -from apps.third.models import BltBind, TDevice, Tlog +from apps.hrm.serializers import EmployeeSimpleSerializer, EmployeeShortSerializer +from apps.third.models import BltBind, TDevice, Tlog, DoorAuth from apps.utils.serializers import CustomModelSerializer from django.core.cache import cache @@ -23,6 +23,7 @@ class TDeviceSerializer(CustomModelSerializer): def get_mtask_(self, obj): return cache.get('vchannel_' + obj.code, {}) + class TDeviceUpdateSerializer(CustomModelSerializer): class Meta: model = TDevice @@ -30,7 +31,8 @@ class TDeviceUpdateSerializer(CustomModelSerializer): def update(self, instance, validated_data): if validated_data.get('access_list', []): - validated_data['access_list'] = ['employee', 'remployee', 'visitor'] + validated_data['access_list'] = [ + 'employee', 'remployee', 'visitor'] return super().update(instance, validated_data) @@ -48,10 +50,14 @@ class RequestCommonSerializer(serializers.Serializer): ('delete', 'delete') ) url = serializers.CharField(label='请求地址', required=False) - method = serializers.ChoiceField(label='请求方法', choices=method_choice, required=False) - params = serializers.JSONField(label='请求参数', required=False, allow_null=True) - json = serializers.JSONField(label='请求body(json格式)', required=False, allow_null=True) - code = serializers.CharField(label='请求短标识', required=False, allow_null=True) + method = serializers.ChoiceField( + label='请求方法', choices=method_choice, required=False) + params = serializers.JSONField( + label='请求参数', required=False, allow_null=True) + json = serializers.JSONField( + label='请求body(json格式)', required=False, allow_null=True) + code = serializers.CharField( + label='请求短标识', required=False, allow_null=True) class BindAreaSerializer(serializers.Serializer): @@ -90,7 +96,8 @@ class BltSerializer(serializers.ModelSerializer): class BltQuerySerializer(serializers.ModelSerializer): - depts = serializers.ListField(child=serializers.CharField(), label="部门ID列表", required=False) + depts = serializers.ListField( + child=serializers.CharField(), label="部门ID列表", required=False) class Meta: model = TDevice @@ -107,4 +114,14 @@ class BltBindCreateSerializer(serializers.ModelSerializer): class BltCreatesSerializer(serializers.Serializer): - macs = serializers.ListField(child=serializers.CharField(), label='标签mac列表') + macs = serializers.ListField( + child=serializers.CharField(), label='标签mac列表') + + +class DoorAuthSerializer(CustomModelSerializer): + employee_ = EmployeeShortSerializer(source='employee', read_only=True) + dchannel_ = TDeviceSimpleSerializer(source='dchannel', read_only=True) + + class Meta: + model = DoorAuth + fields = '__all__' diff --git a/apps/third/tapis.py b/apps/third/tapis.py index 6378e351..b3e8187a 100755 --- a/apps/third/tapis.py +++ b/apps/third/tapis.py @@ -68,6 +68,10 @@ dhapis = { "url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/doorAuthority", "method": "post" }, + "card_door_authority_delete": { + "url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/doorAuthority/deleteSingleCardPrivilege", + "method": "post" + }, "mq_subscribe": { "url": "/evo-apigw/evo-event/1.0.0/subscribe/mqinfo", "method": "post" diff --git a/apps/third/urls.py b/apps/third/urls.py index 219bf3c0..45d5f641 100755 --- a/apps/third/urls.py +++ b/apps/third/urls.py @@ -2,7 +2,7 @@ from email.mime import base from django.urls import path, include from rest_framework import routers from apps.third.views import DahuaTestView, DhCommonViewSet, SpTestView, SpeakerViewSet, XxCommonViewSet, XxTestView -from apps.third.views_d import BltViewSet, TDeviceViewSet, TlogViewSet +from apps.third.views_d import BltViewSet, TDeviceViewSet, TlogViewSet, DoorAuthViewSet API_BASE_URL = 'api/third/' HTML_BASE_URL = 'third/' @@ -14,6 +14,7 @@ router.register('speaker', SpeakerViewSet, basename='api_speaker') router.register('tdevice', TDeviceViewSet, basename='tdevice') router.register('tlog', TlogViewSet, basename='tlog') router.register('tdevice/blt', BltViewSet, basename='blt') +router.register('doorauth', DoorAuthViewSet, basename='doorauth') urlpatterns = [ path(API_BASE_URL, include(router.urls)), path(API_BASE_URL + 'dahua/test/', DahuaTestView.as_view()), diff --git a/apps/third/views_d.py b/apps/third/views_d.py index 6fe5c414..a83e1ea4 100644 --- a/apps/third/views_d.py +++ b/apps/third/views_d.py @@ -1,6 +1,6 @@ from apps.third.filters import TDeviceFilterSet -from apps.third.models import BltBind, TDevice, Tlog -from apps.third.serializers import BindAreaSerializer, BltBindCreateSerializer, BltQuerySerializer, BltSerializer, LabelLocationSerializer, TDeviceSerializer, TDeviceUpdateSerializer, TlogSerializer +from apps.third.models import BltBind, TDevice, Tlog, DoorAuth +from apps.third.serializers import BindAreaSerializer, BltBindCreateSerializer, BltQuerySerializer, BltSerializer, LabelLocationSerializer, TDeviceSerializer, TDeviceUpdateSerializer, TlogSerializer, DoorAuthSerializer from apps.utils.viewsets import CustomGenericViewSet from rest_framework.mixins import ListModelMixin, CreateModelMixin from apps.third.dahua import dhClient @@ -131,13 +131,15 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom """ 三方设备接口 """ - perms_map = {'get': '*', 'put': 'tdevice.update', 'delete': 'tdevice.delete'} + perms_map = {'get': '*', 'put': 'tdevice.update', + 'delete': 'tdevice.delete'} queryset = TDevice.objects.all() serializer_class = TDeviceSerializer update_serializer_class = TDeviceUpdateSerializer ordering = ['-create_time'] filterset_class = TDeviceFilterSet - select_related_fields = ['employee', 'area', 'employee__post', 'employee__belong_dept'] + select_related_fields = ['employee', 'area', + 'employee__post', 'employee__belong_dept'] def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) @@ -170,7 +172,7 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom 'includeSubOwnerCodeFlag': True, 'channelCodeList': codes, 'pageSize': len(codes) - } + } _, res = dhClient.request(**dhapis['channel_list'], json=json) codes_dict = {} for i in res['pageData']: @@ -211,7 +213,7 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom # ckey = 'vchannel_' + id # cache.delete(ckey) # return Response() - + @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer) @transaction.atomic @@ -227,7 +229,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom _, res = xxClient.request(**xxapis['blt_list'], json=json) blt_list = res['recordList'] for i in blt_list: - TDevice.objects.get_or_create(code=i['mac'], defaults={"code": i['mac'], "type": TDevice.DEVICE_BLT}) + TDevice.objects.get_or_create(code=i['mac'], defaults={ + "code": i['mac'], "type": TDevice.DEVICE_BLT}) return Response() @action(methods=['post'], detail=False, perms_map={'post': '*'}, @@ -254,7 +257,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom td = TDevice(code=i['sn'], type=TDevice.DEVICE_SPEAKER) td.name = i['name'] td.save() - TDevice.objects.filter(type=TDevice.DEVICE_SPEAKER).exclude(code__in=t_l).delete() # 移除不需要的 + TDevice.objects.filter(type=TDevice.DEVICE_SPEAKER).exclude( + code__in=t_l).delete() # 移除不需要的 return Response() @action(methods=['post'], detail=False, perms_map={'post': '*'}, @@ -280,10 +284,12 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom if td: pass else: - td = TDevice(code=i['channelCode'], type=TDevice.DEVICE_VCHANNEL) + td = TDevice(code=i['channelCode'], + type=TDevice.DEVICE_VCHANNEL) td.name = i['channelName'] td.save() - TDevice.objects.filter(type=TDevice.DEVICE_VCHANNEL).exclude(code__in=t_l).delete() + TDevice.objects.filter(type=TDevice.DEVICE_VCHANNEL).exclude( + code__in=t_l).delete() return Response() @action(methods=['post'], detail=False, perms_map={'post': '*'}, @@ -307,7 +313,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom if td: pass else: - td = TDevice(code=i['channelCode'], type=TDevice.DEVICE_DCHANNEL) + td = TDevice(code=i['channelCode'], + type=TDevice.DEVICE_DCHANNEL) td.name = i['channelName'] # td.access_list = ['employee', 'remployee', 'visitor'] td.save() @@ -325,7 +332,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom serializer.is_valid(raise_exception=True) vdata = serializer.validated_data code = vdata['code'] - blt = TDevice.objects.filter(code=code, type=TDevice.DEVICE_BLT).first() + blt = TDevice.objects.filter( + code=code, type=TDevice.DEVICE_BLT).first() if blt: if vdata['type'] == BltBind.BLT_BIND and vdata['employee']: if blt.employee: @@ -385,13 +393,14 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom request.data.update({ 'unitTypeList': ["1"], 'includeSubOwnerCodeFlag': True - }) + }) _, res = dhClient.request(**dhapis['channel_list'], json=request.data) codes = [] if res.get('pageData', None): for i in res['pageData']: codes.append(i['channelCode']) - tds_info = TDeviceSerializer(instance=TDevice.objects.filter(code__in=codes), many=True).data + tds_info = TDeviceSerializer( + instance=TDevice.objects.filter(code__in=codes), many=True).data tds_dict = {} for i in tds_info: tds_dict[i['code']] = i @@ -414,7 +423,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom codes = [] for i in res['rows']: codes.append(i['sn']) - tds_info = TDeviceSerializer(instance=TDevice.objects.filter(code__in=codes), many=True).data + tds_info = TDeviceSerializer( + instance=TDevice.objects.filter(code__in=codes), many=True).data tds_dict = {} for i in tds_info: tds_dict[i['code']] = i @@ -435,13 +445,14 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom request.data.update({ 'unitTypeList': ["7"], 'includeSubOwnerCodeFlag': True - }) + }) _, res = dhClient.request(**dhapis['channel_list'], json=request.data) codes = [] if res.get('pageData', None): for i in res['pageData']: codes.append(i['channelCode']) - tds_info = TDeviceSerializer(instance=TDevice.objects.filter(code__in=codes), many=True).data + tds_info = TDeviceSerializer( + instance=TDevice.objects.filter(code__in=codes), many=True).data tds_dict = {} for i in tds_info: tds_dict[i['code']] = i @@ -527,3 +538,29 @@ class TlogViewSet(ListModelMixin, CustomGenericViewSet): queryset = Tlog.objects.all() serializer_class = TlogSerializer filterset_fields = ['result', 'id'] + + +class DoorAuthViewSet(ListModelMixin, DestroyModelMixin, CustomGenericViewSet): + """ + list: 门禁权限 + + 门禁权限 + """ + perms_map = {'get': '*', 'delete': 'doorauth.delete'} + queryset = DoorAuth.objects.all() + serializer_class = DoorAuthSerializer + filterset_fields = ['dchannel', 'employee'] + select_related_fields = ['dchannel', 'employee'] + search_fields = ['employee__name'] + + @transaction.atomic + def perform_destroy(self, instance): + dh_face_card = instance.employee.third_info['dh_face_card'] + rdict = { + "cardNumber": dh_face_card, + "cardPrivilegeDetails": [ + {"privilegeType": 1, "resouceCode": instance.dchannel.code}, + ] + } + dhClient.request(**dhapis['card_door_authority_delete'], json=rdict) + instance.delete()