feat: 查看门禁权限并支持删除

This commit is contained in:
caoqianming 2023-10-09 11:09:31 +08:00
parent b4cc887f79
commit b479db9f89
8 changed files with 247 additions and 98 deletions

View File

@ -17,14 +17,25 @@ from rest_framework.exceptions import ParseError
from django.conf import settings 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): 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) post_name = serializers.CharField(source='post.name', read_only=True)
location = serializers.SerializerMethodField() location = serializers.SerializerMethodField()
class Meta: class Meta:
model = Employee 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): def get_location(self, obj):
key_str = 'ep_{}'.format(obj.id) key_str = 'ep_{}'.format(obj.id)
@ -40,7 +51,8 @@ class EmployeeSimpleSerializer(CustomModelSerializer):
class EmployeeCreateUpdateSerializer(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: class Meta:
model = Employee model = Employee
@ -72,7 +84,8 @@ class EmployeeCreateUpdateSerializer(CustomModelSerializer):
instance = super().update(instance, validated_data) instance = super().update(instance, validated_data)
if old_photo != instance.photo: # 如果照片有变动,需要更新人脸库 if old_photo != instance.photo: # 如果照片有变动,需要更新人脸库
# 使用的是face_recongition # 使用的是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 in_face_data = instance.face_data
if face_data: if face_data:
if isinstance(in_face_data, dict): if isinstance(in_face_data, dict):
@ -104,17 +117,19 @@ class EmployeeCreateUpdateSerializer(CustomModelSerializer):
if instance.type in ['employee', 'remployee']: if instance.type in ['employee', 'remployee']:
start_time = None start_time = None
end_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 start_time = now
end_time = now + timedelta(days=7300) end_time = now + timedelta(days=7300)
if instance.job_state in [20, 30] and old_job_state == 10: # 离职或退休 if instance.job_state in [20, 30] and old_job_state == 10: # 离职或退休
start_time = now start_time = now
end_time = now + timedelta(hours=8) 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 start_time = now
end_time = now + timedelta(days=7300) end_time = now + timedelta(days=7300)
HrmService.sync_dahua_employee(ep=instance, old_photo=old_photo, 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 return instance
@ -124,7 +139,8 @@ class EmployeeImproveSerializer(CustomModelSerializer):
class Meta: class Meta:
model = Employee 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 = { extra_kwargs = {
'number': {'required': True}, 'number': {'required': True},
'photo': {'required': True}, 'photo': {'required': True},
@ -147,7 +163,8 @@ class ChannelAuthoritySerializer(serializers.Serializer):
class EmployeeSerializer(CustomModelSerializer): class EmployeeSerializer(CustomModelSerializer):
belong_dept_ = DeptSimpleSerializer(source='belong_dept', read_only=True) belong_dept_ = DeptSimpleSerializer(source='belong_dept', read_only=True)
user_ = UserSimpleSerializer(source='user', 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) post_name = serializers.CharField(source='post.name', read_only=True)
blt_ = serializers.SerializerMethodField() blt_ = serializers.SerializerMethodField()
photo_f = MyFilePathField(source='photo', read_only=True) photo_f = MyFilePathField(source='photo', read_only=True)
@ -161,7 +178,7 @@ class EmployeeSerializer(CustomModelSerializer):
def get_blt_(self, obj): def get_blt_(self, obj):
if hasattr(obj, 'blt'): if hasattr(obj, 'blt'):
from apps.third.serializers import TDeviceSimpleSerializer from apps.third.serializers import TDeviceSimpleSerializer
return TDeviceSimpleSerializer(instance=obj.blt).data return TDeviceSimpleSerializer(instance=obj.blt).data
# if hasattr(obj, 'tdevice'): # if hasattr(obj, 'tdevice'):
# from apps.third.serializers import TDeviceSimpleSerializer # from apps.third.serializers import TDeviceSimpleSerializer
# return TDeviceSimpleSerializer(instance=obj.tdevice).data # return TDeviceSimpleSerializer(instance=obj.tdevice).data
@ -197,6 +214,7 @@ class ClockRecordListSerializer(serializers.ModelSerializer):
model = ClockRecord model = ClockRecord
fields = '__all__' fields = '__all__'
class ClockRecordSimpleSerializer(serializers.ModelSerializer): class ClockRecordSimpleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = ClockRecord model = ClockRecord
@ -218,7 +236,8 @@ class CertificateCreateUpdateSerializer(CustomModelSerializer):
class CertificateSerializer(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) file_f = MyFilePathField(source='file', read_only=True)
class Meta: class Meta:
@ -228,4 +247,4 @@ class CertificateSerializer(CustomModelSerializer):
class CorrectSerializer(serializers.Serializer): class CorrectSerializer(serializers.Serializer):
start_time = serializers.DateTimeField() start_time = serializers.DateTimeField()
end_time = serializers.DateTimeField() end_time = serializers.DateTimeField()

View File

@ -34,7 +34,7 @@ class HrmService:
Returns: Returns:
_type_: _description_ _type_: _description_
""" """
if not settings.DAHUA_ENABLED: # 如果大华没启用, 直接返回 if not settings.DAHUA_ENABLED: # 如果大华没启用, 直接返回
return return
dh_id = ep.third_info.get('dh_id', None) dh_id = ep.third_info.get('dh_id', None)
dh_photo = ep.third_info.get('dh_photo', None) dh_photo = ep.third_info.get('dh_photo', None)
@ -68,7 +68,8 @@ class HrmService:
}] }]
} }
if ep.photo != old_photo and ep.photo: 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"] dh_photo = res["fileUrl"]
json_data.update( json_data.update(
{ {
@ -98,7 +99,8 @@ class HrmService:
"email": ep.email, "email": ep.email,
"sex": 1 if ep.gender == '' else 2 "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"] dh_photo = res["fileUrl"]
json_data.update( json_data.update(
{ {
@ -129,16 +131,20 @@ class HrmService:
if start_time is None: # 如果时间段未提供,跳过更新操作 if start_time is None: # 如果时间段未提供,跳过更新操作
pass pass
else: else:
startDate = timezone.localtime(start_time).strftime("%Y-%m-%d %H:%M:%S") startDate = timezone.localtime(
endDate = timezone.localtime(end_time).strftime("%Y-%m-%d %H:%M:%S") start_time).strftime("%Y-%m-%d %H:%M:%S")
endDate = timezone.localtime(
end_time).strftime("%Y-%m-%d %H:%M:%S")
json_data = { json_data = {
"cardNumber": cardNumber, "cardNumber": cardNumber,
"startDate": startDate, "startDate": startDate,
"endDate": endDate, "endDate": endDate,
"departmentId": departmentId, "departmentId": departmentId,
} }
_, res = dhClient.request(**dhapis['card_update'], json=json_data) _, res = dhClient.request(
cls.save(ep, data={'dh_face_card_start': startDate, 'dh_face_card_end': endDate}) **dhapis['card_update'], json=json_data)
cls.save(
ep, data={'dh_face_card_start': startDate, 'dh_face_card_end': endDate})
return cardNumber return cardNumber
else: else:
_, res = dhClient.request(**dhapis['card_gen_id']) _, res = dhClient.request(**dhapis['card_gen_id'])
@ -147,10 +153,13 @@ class HrmService:
if start_time is None: # 如果未规定时间范围, 默认1小时 if start_time is None: # 如果未规定时间范围, 默认1小时
now = datetime.now() now = datetime.now()
startDate = now.strftime("%Y-%m-%d %H:%M:%S") 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: else:
startDate = timezone.localtime(start_time).strftime("%Y-%m-%d %H:%M:%S") startDate = timezone.localtime(
endDate = timezone.localtime(end_time).strftime("%Y-%m-%d %H:%M:%S") start_time).strftime("%Y-%m-%d %H:%M:%S")
endDate = timezone.localtime(
end_time).strftime("%Y-%m-%d %H:%M:%S")
json_data = { json_data = {
"id": cardId, "id": cardId,
"cardNumber": cardNumber, "cardNumber": cardNumber,
@ -180,7 +189,9 @@ class HrmService:
from apps.third.models import TDevice from apps.third.models import TDevice
dh_face_card = ep.third_info.get('dh_face_card', None) dh_face_card = ep.third_info.get('dh_face_card', None)
if dh_dchannels: if dh_dchannels:
pass # 只分配系统里有的
dh_dchannels = list(TDevice.objects.filter(
code__in=dh_dchannels).values_list('code', flat=True))
else: else:
# 查找可授予的门禁通道号 # 查找可授予的门禁通道号
dh_dchannels = list(TDevice.objects.filter(type=TDevice.DEVICE_DCHANNEL, dh_dchannels = list(TDevice.objects.filter(type=TDevice.DEVICE_DCHANNEL,
@ -201,7 +212,8 @@ class HrmService:
while ind < 8: while ind < 8:
time.sleep(6) time.sleep(6)
try: try:
dhClient.request(**dhapis['card_door_authority'], json=json_data) dhClient.request(
**dhapis['card_door_authority'], json=json_data)
break break
except Exception as e: except Exception as e:
ind = ind + 1 ind = ind + 1
@ -220,6 +232,13 @@ class HrmService:
# elif is_ok == 'error': # elif is_ok == 'error':
# raise APIException(**DH_REQUEST_ERROR) # raise APIException(**DH_REQUEST_ERROR)
cls.save(ep, data={'dh_dchannels': dh_dchannels}) 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 return dh_dchannels
@classmethod @classmethod
@ -243,10 +262,11 @@ class HrmService:
nodeCode = data['info']['extend']['acsChannelCode'] nodeCode = data['info']['extend']['acsChannelCode']
swip_time = data['info']['extend']['swingTime'] swip_time = data['info']['extend']['swingTime']
e_type = data['info']['extend']['enterOrExit'] 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 @classmethod
def swipe_offline(cls, data:dict): def swipe_offline(cls, data: dict):
"""离线刷卡推送记录处理 """离线刷卡推送记录处理
""" """
for i in data['infoArray']: for i in data['infoArray']:
@ -256,9 +276,9 @@ class HrmService:
swip_time = i['swingTime'] swip_time = i['swingTime']
e_type = i['enterOrExit'] e_type = i['enterOrExit']
cls.swipe_next(nodeCode, id_number, swip_time, e_type, i) cls.swipe_next(nodeCode, id_number, swip_time, e_type, i)
@classmethod @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.rpm.models import Rpj
from apps.vm.models import Visit from apps.vm.models import Visit
@ -267,15 +287,17 @@ class HrmService:
state=Visit.V_WORKING) state=Visit.V_WORKING)
Rpj.objects.filter(state=Rpj.RPJ_ENTER, remployees__employee__id_number=id_number).update( Rpj.objects.filter(state=Rpj.RPJ_ENTER, remployees__employee__id_number=id_number).update(
state=Rpj.RPJ_WORKING) state=Rpj.RPJ_WORKING)
# 打卡处理 # 打卡处理
device = TDevice.objects.filter(code=nodeCode).first() 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: if device and device.is_clock and ep:
tzinfo = tz.gettz('Asia/Shanghai') 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, 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, 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) hour=23, minute=59, second=59, tzinfo=tzinfo)
@ -288,13 +310,13 @@ class HrmService:
card_type = 20 card_type = 20
elif e_type == 3: elif e_type == 3:
time_10_x = datetime(year=s_time_f.year, month=s_time_f.month, 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, 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, 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, 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: if time_10_x < s_time_f < time_10_y:
card_type = 10 card_type = 10
elif time_20_x < s_time_f < time_20_y: elif time_20_x < s_time_f < time_20_y:
@ -302,9 +324,10 @@ class HrmService:
if card_type == 30: if card_type == 30:
note = '非打卡时间范围' note = '非打卡时间范围'
trigger = 'panel' 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: if cr:
pass pass
else: else:
@ -312,7 +335,7 @@ class HrmService:
cr.employee = ep cr.employee = ep
cr.create_time = s_time_f cr.create_time = s_time_f
cr.type = card_type cr.type = card_type
cr.exception_type = None cr.exception_type = None
cr.trigger = trigger cr.trigger = trigger
cr.detail = detail cr.detail = detail
cr.note = note cr.note = note
@ -323,34 +346,38 @@ class HrmService:
cr_10_q = ClockRecord.objects.filter( cr_10_q = ClockRecord.objects.filter(
type=10, employee=ep, create_time__gte=first_time, create_time__lte=end_time) type=10, employee=ep, create_time__gte=first_time, create_time__lte=end_time)
first_obj = cr_10_q.order_by('create_time').first() 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: elif card_type == 20:
# 查找当天的出门记录 # 查找当天的出门记录
cr_20_q = ClockRecord.objects.filter( cr_20_q = ClockRecord.objects.filter(
type=20, employee=ep, create_time__gte=first_time, create_time__lte=end_time) type=20, employee=ep, create_time__gte=first_time, create_time__lte=end_time)
last_obj = cr_20_q.order_by('-create_time').first() 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: if cr_e and last_obj:
time_d = last_obj.create_time - cr_e.create_time time_d = last_obj.create_time - cr_e.create_time
if cr_e.type == 10: 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.exception_type = ClockRecord.E_TYPE_LESS
last_obj.save() 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.exception_type = ClockRecord.E_TYPE_MORE
last_obj.save() 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.exception_type = ClockRecord.E_TYPE_ADD
last_obj.save() last_obj.save()
elif cr_e.type == 20: elif cr_e.type == 20:
last_obj.exception_type = ClockRecord.E_TYPE_MISS last_obj.exception_type = ClockRecord.E_TYPE_MISS
last_obj.save() 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: if last_obj_t:
update_fields = {'last_check_time': last_obj_t.create_time} update_fields = {'last_check_time': last_obj_t.create_time}
if last_obj_t.type == 10: if last_obj_t.type == 10:
@ -358,48 +385,48 @@ class HrmService:
else: else:
update_fields['is_atwork'] = False update_fields['is_atwork'] = False
Employee.objects.filter(id=ep.id).update(**update_fields) Employee.objects.filter(id=ep.id).update(**update_fields)
# 此处可触发安全帽事件逻辑 # 此处可触发安全帽事件逻辑
@classmethod @classmethod
def get_facedata_from_img_x(cls, img_path): def get_facedata_from_img_x(cls, img_path):
import face_recognition import face_recognition
try: try:
picture_of_me = face_recognition.load_image_file(img_path) 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() face_data_list = my_face_encoding.tolist()
return face_data_list, '' return face_data_list, ''
except: except:
return None, '人脸数据获取失败请重新上传图片' return None, '人脸数据获取失败请重新上传图片'
@classmethod @classmethod
def face_compare_from_base64(cls, base64_data): def face_compare_from_base64(cls, base64_data):
import face_recognition import face_recognition
filename = str(uuid.uuid4()) 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: with open(filepath, 'wb') as f:
f.write(base64_data) f.write(base64_data)
try: try:
unknown_picture = face_recognition.load_image_file(filepath) 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) os.remove(filepath)
except: except:
os.remove(filepath) os.remove(filepath)
return None, '识别失败,请调整位置' 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: if face_datas is None:
from apps.hrm.tasks import update_all_facedata_cache from apps.hrm.tasks import update_all_facedata_cache
update_all_facedata_cache() update_all_facedata_cache()
face_datas = cache.get('face_datas_dlib') face_datas = cache.get('face_datas_dlib')
results = face_recognition.compare_faces(face_datas['datas'], results = face_recognition.compare_faces(face_datas['datas'],
unknown_face_encoding, tolerance=0.45) unknown_face_encoding, tolerance=0.45)
face_distances = face_recognition.face_distance(face_datas['datas'], unknown_face_encoding) face_distances = face_recognition.face_distance(
face_datas['datas'], unknown_face_encoding)
best_match_index = np.argmin(face_distances) best_match_index = np.argmin(face_distances)
if results[best_match_index]: if results[best_match_index]:
epId = face_datas['eps'][best_match_index] epId = face_datas['eps'][best_match_index]
@ -408,7 +435,7 @@ class HrmService:
# first_match_index = results.index(True) # first_match_index = results.index(True)
# # 识别成功 # # 识别成功
# ep = Employee.objects.get(id=face_datas['eps'][first_match_index]) # ep = Employee.objects.get(id=face_datas['eps'][first_match_index])
# return ep, '' # return ep, ''
return None, '人脸未匹配,请调整位置' return None, '人脸未匹配,请调整位置'
@classmethod @classmethod
@ -416,7 +443,7 @@ class HrmService:
from apps.utils.face import face_find from apps.utils.face import face_find
# from deepface import DeepFace # from deepface import DeepFace
img_name = str(uuid.uuid4()) 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: with open(img_path, 'wb') as f:
f.write(base64_data) f.write(base64_data)
# db_path = os.path.join(settings.BASE_DIR, 'media/face') # db_path = os.path.join(settings.BASE_DIR, 'media/face')
@ -443,7 +470,8 @@ class HrmService:
def get_facedata_from_img(cls, img_path): def get_facedata_from_img(cls, img_path):
try: try:
from deepface import DeepFace 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"], '' return embedding_objs[0]["embedding"], ''
except Exception as e: except Exception as e:
return None, '人脸数据获取失败请重新上传图片' return None, '人脸数据获取失败请重新上传图片'

View File

@ -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,
},
),
]

View File

@ -31,7 +31,8 @@ class TDevice(BaseModel):
(DEVICE_PANEL, '面板机') (DEVICE_PANEL, '面板机')
) )
type = models.PositiveSmallIntegerField('设备类型', choices=DEVICE_CHOICE) 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) name = models.CharField('名称', max_length=50, null=True, blank=True)
location = models.JSONField('位置信息', default=dict, location = models.JSONField('位置信息', default=dict,
null=False, blank=True) null=False, blank=True)
@ -39,13 +40,15 @@ class TDevice(BaseModel):
verbose_name='所在区', null=True, blank=True) verbose_name='所在区', null=True, blank=True)
areas = models.ManyToManyField(Area, verbose_name='覆盖区', areas = models.ManyToManyField(Area, verbose_name='覆盖区',
related_name='tareas', blank=True) 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, employee = models.OneToOneField(Employee, verbose_name='当前绑定人员', on_delete=models.SET_NULL,
null=True, blank=True, related_name='blt') null=True, blank=True, related_name='blt')
is_clock = models.BooleanField('是否打卡设备', default=False) is_clock = models.BooleanField('是否打卡设备', default=False)
access_list = models.JSONField('自动下发人员类型', default=list, access_list = models.JSONField('自动下发人员类型', default=list,
null=False, blank=True, help_text='employee/remployee/visitor/driver') 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) # algos = models.ManyToManyField('ecm.eventcate', through='ecm.algochannel', blank=True)
third_info = models.JSONField('三方信息', default=dict, third_info = models.JSONField('三方信息', default=dict,
null=False, blank=True) null=False, blank=True)
@ -62,9 +65,12 @@ class BltBind(BaseModel):
) )
type = models.PositiveSmallIntegerField('绑定类型', default=10, help_text='10(绑定)/20(解绑)', type = models.PositiveSmallIntegerField('绑定类型', default=10, help_text='10(绑定)/20(解绑)',
choices=BIND_TYPE_CHOICES) choices=BIND_TYPE_CHOICES)
obj_cate = models.CharField('绑定对象', max_length=20, help_text='people/...', null=True, blank=True) obj_cate = models.CharField(
blt = models.ForeignKey(TDevice, verbose_name='关联标签', on_delete=models.CASCADE) '绑定对象', max_length=20, help_text='people/...', null=True, blank=True)
employee = models.ForeignKey(Employee, verbose_name='关联人员', on_delete=models.CASCADE, 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): class Tlog(BaseModel):
@ -83,3 +89,10 @@ class Tlog(BaseModel):
errors = models.TextField(null=True, blank=True) errors = models.TextField(null=True, blank=True)
params = models.JSONField(null=True, blank=True) params = models.JSONField(null=True, blank=True)
body = 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)

View File

@ -1,8 +1,8 @@
from rest_framework import serializers from rest_framework import serializers
from apps.am.models import Area from apps.am.models import Area
from apps.hrm.serializers import EmployeeSimpleSerializer from apps.hrm.serializers import EmployeeSimpleSerializer, EmployeeShortSerializer
from apps.third.models import BltBind, TDevice, Tlog from apps.third.models import BltBind, TDevice, Tlog, DoorAuth
from apps.utils.serializers import CustomModelSerializer from apps.utils.serializers import CustomModelSerializer
from django.core.cache import cache from django.core.cache import cache
@ -23,6 +23,7 @@ class TDeviceSerializer(CustomModelSerializer):
def get_mtask_(self, obj): def get_mtask_(self, obj):
return cache.get('vchannel_' + obj.code, {}) return cache.get('vchannel_' + obj.code, {})
class TDeviceUpdateSerializer(CustomModelSerializer): class TDeviceUpdateSerializer(CustomModelSerializer):
class Meta: class Meta:
model = TDevice model = TDevice
@ -30,7 +31,8 @@ class TDeviceUpdateSerializer(CustomModelSerializer):
def update(self, instance, validated_data): def update(self, instance, validated_data):
if validated_data.get('access_list', []): 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) return super().update(instance, validated_data)
@ -48,10 +50,14 @@ class RequestCommonSerializer(serializers.Serializer):
('delete', 'delete') ('delete', 'delete')
) )
url = serializers.CharField(label='请求地址', required=False) url = serializers.CharField(label='请求地址', required=False)
method = serializers.ChoiceField(label='请求方法', choices=method_choice, required=False) method = serializers.ChoiceField(
params = serializers.JSONField(label='请求参数', required=False, allow_null=True) label='请求方法', choices=method_choice, required=False)
json = serializers.JSONField(label='请求body(json格式)', required=False, allow_null=True) params = serializers.JSONField(
code = serializers.CharField(label='请求短标识', required=False, allow_null=True) 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): class BindAreaSerializer(serializers.Serializer):
@ -90,7 +96,8 @@ class BltSerializer(serializers.ModelSerializer):
class BltQuerySerializer(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: class Meta:
model = TDevice model = TDevice
@ -107,4 +114,14 @@ class BltBindCreateSerializer(serializers.ModelSerializer):
class BltCreatesSerializer(serializers.Serializer): 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__'

View File

@ -68,6 +68,10 @@ dhapis = {
"url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/doorAuthority", "url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/doorAuthority",
"method": "post" "method": "post"
}, },
"card_door_authority_delete": {
"url": "/evo-apigw/evo-accesscontrol/1.0.0/card/accessControl/doorAuthority/deleteSingleCardPrivilege",
"method": "post"
},
"mq_subscribe": { "mq_subscribe": {
"url": "/evo-apigw/evo-event/1.0.0/subscribe/mqinfo", "url": "/evo-apigw/evo-event/1.0.0/subscribe/mqinfo",
"method": "post" "method": "post"

View File

@ -2,7 +2,7 @@ from email.mime import base
from django.urls import path, include from django.urls import path, include
from rest_framework import routers from rest_framework import routers
from apps.third.views import DahuaTestView, DhCommonViewSet, SpTestView, SpeakerViewSet, XxCommonViewSet, XxTestView 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/' API_BASE_URL = 'api/third/'
HTML_BASE_URL = 'third/' HTML_BASE_URL = 'third/'
@ -14,6 +14,7 @@ router.register('speaker', SpeakerViewSet, basename='api_speaker')
router.register('tdevice', TDeviceViewSet, basename='tdevice') router.register('tdevice', TDeviceViewSet, basename='tdevice')
router.register('tlog', TlogViewSet, basename='tlog') router.register('tlog', TlogViewSet, basename='tlog')
router.register('tdevice/blt', BltViewSet, basename='blt') router.register('tdevice/blt', BltViewSet, basename='blt')
router.register('doorauth', DoorAuthViewSet, basename='doorauth')
urlpatterns = [ urlpatterns = [
path(API_BASE_URL, include(router.urls)), path(API_BASE_URL, include(router.urls)),
path(API_BASE_URL + 'dahua/test/', DahuaTestView.as_view()), path(API_BASE_URL + 'dahua/test/', DahuaTestView.as_view()),

View File

@ -1,6 +1,6 @@
from apps.third.filters import TDeviceFilterSet from apps.third.filters import TDeviceFilterSet
from apps.third.models import BltBind, TDevice, Tlog from apps.third.models import BltBind, TDevice, Tlog, DoorAuth
from apps.third.serializers import BindAreaSerializer, BltBindCreateSerializer, BltQuerySerializer, BltSerializer, LabelLocationSerializer, TDeviceSerializer, TDeviceUpdateSerializer, TlogSerializer from apps.third.serializers import BindAreaSerializer, BltBindCreateSerializer, BltQuerySerializer, BltSerializer, LabelLocationSerializer, TDeviceSerializer, TDeviceUpdateSerializer, TlogSerializer, DoorAuthSerializer
from apps.utils.viewsets import CustomGenericViewSet from apps.utils.viewsets import CustomGenericViewSet
from rest_framework.mixins import ListModelMixin, CreateModelMixin from rest_framework.mixins import ListModelMixin, CreateModelMixin
from apps.third.dahua import dhClient 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() queryset = TDevice.objects.all()
serializer_class = TDeviceSerializer serializer_class = TDeviceSerializer
update_serializer_class = TDeviceUpdateSerializer update_serializer_class = TDeviceUpdateSerializer
ordering = ['-create_time'] ordering = ['-create_time']
filterset_class = TDeviceFilterSet 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): def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset()) queryset = self.filter_queryset(self.get_queryset())
@ -170,7 +172,7 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
'includeSubOwnerCodeFlag': True, 'includeSubOwnerCodeFlag': True,
'channelCodeList': codes, 'channelCodeList': codes,
'pageSize': len(codes) 'pageSize': len(codes)
} }
_, res = dhClient.request(**dhapis['channel_list'], json=json) _, res = dhClient.request(**dhapis['channel_list'], json=json)
codes_dict = {} codes_dict = {}
for i in res['pageData']: for i in res['pageData']:
@ -211,7 +213,7 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
# ckey = 'vchannel_' + id # ckey = 'vchannel_' + id
# cache.delete(ckey) # cache.delete(ckey)
# return Response() # return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'}, @action(methods=['post'], detail=False, perms_map={'post': '*'},
serializer_class=Serializer) serializer_class=Serializer)
@transaction.atomic @transaction.atomic
@ -227,7 +229,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
_, res = xxClient.request(**xxapis['blt_list'], json=json) _, res = xxClient.request(**xxapis['blt_list'], json=json)
blt_list = res['recordList'] blt_list = res['recordList']
for i in blt_list: 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() return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'}, @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 = TDevice(code=i['sn'], type=TDevice.DEVICE_SPEAKER)
td.name = i['name'] td.name = i['name']
td.save() 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() return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'}, @action(methods=['post'], detail=False, perms_map={'post': '*'},
@ -280,10 +284,12 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
if td: if td:
pass pass
else: else:
td = TDevice(code=i['channelCode'], type=TDevice.DEVICE_VCHANNEL) td = TDevice(code=i['channelCode'],
type=TDevice.DEVICE_VCHANNEL)
td.name = i['channelName'] td.name = i['channelName']
td.save() 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() return Response()
@action(methods=['post'], detail=False, perms_map={'post': '*'}, @action(methods=['post'], detail=False, perms_map={'post': '*'},
@ -307,7 +313,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
if td: if td:
pass pass
else: else:
td = TDevice(code=i['channelCode'], type=TDevice.DEVICE_DCHANNEL) td = TDevice(code=i['channelCode'],
type=TDevice.DEVICE_DCHANNEL)
td.name = i['channelName'] td.name = i['channelName']
# td.access_list = ['employee', 'remployee', 'visitor'] # td.access_list = ['employee', 'remployee', 'visitor']
td.save() td.save()
@ -325,7 +332,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data vdata = serializer.validated_data
code = vdata['code'] 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 blt:
if vdata['type'] == BltBind.BLT_BIND and vdata['employee']: if vdata['type'] == BltBind.BLT_BIND and vdata['employee']:
if blt.employee: if blt.employee:
@ -385,13 +393,14 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
request.data.update({ request.data.update({
'unitTypeList': ["1"], 'unitTypeList': ["1"],
'includeSubOwnerCodeFlag': True 'includeSubOwnerCodeFlag': True
}) })
_, res = dhClient.request(**dhapis['channel_list'], json=request.data) _, res = dhClient.request(**dhapis['channel_list'], json=request.data)
codes = [] codes = []
if res.get('pageData', None): if res.get('pageData', None):
for i in res['pageData']: for i in res['pageData']:
codes.append(i['channelCode']) 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 = {} tds_dict = {}
for i in tds_info: for i in tds_info:
tds_dict[i['code']] = i tds_dict[i['code']] = i
@ -414,7 +423,8 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
codes = [] codes = []
for i in res['rows']: for i in res['rows']:
codes.append(i['sn']) 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 = {} tds_dict = {}
for i in tds_info: for i in tds_info:
tds_dict[i['code']] = i tds_dict[i['code']] = i
@ -435,13 +445,14 @@ class TDeviceViewSet(ListModelMixin, UpdateModelMixin, DestroyModelMixin, Custom
request.data.update({ request.data.update({
'unitTypeList': ["7"], 'unitTypeList': ["7"],
'includeSubOwnerCodeFlag': True 'includeSubOwnerCodeFlag': True
}) })
_, res = dhClient.request(**dhapis['channel_list'], json=request.data) _, res = dhClient.request(**dhapis['channel_list'], json=request.data)
codes = [] codes = []
if res.get('pageData', None): if res.get('pageData', None):
for i in res['pageData']: for i in res['pageData']:
codes.append(i['channelCode']) 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 = {} tds_dict = {}
for i in tds_info: for i in tds_info:
tds_dict[i['code']] = i tds_dict[i['code']] = i
@ -527,3 +538,29 @@ class TlogViewSet(ListModelMixin, CustomGenericViewSet):
queryset = Tlog.objects.all() queryset = Tlog.objects.all()
serializer_class = TlogSerializer serializer_class = TlogSerializer
filterset_fields = ['result', 'id'] 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()