from rest_framework.exceptions import ParseError, APIException import logging import time from apps.hrm.models import ClockRecord, Employee from apps.third.errors import DH_REQUEST_ERROR from apps.third.models import TDevice from apps.third.tapis import dhapis from apps.third.dahua import dhClient from apps.utils.tools import rannum, ranstr from datetime import datetime from django.utils import timezone myLogger = logging.getLogger('log') class HrmService: @classmethod def sync_dahua_employee(cls, ep: Employee, old_photo='', start_time=None, end_time=None): """同步大华信息(员工/卡片/门禁) Args: ep (Employee): 人员实例 old_photo (str, optional): 原照片地址. Defaults to ''. start_time (_type_, optional): 开人脸卡起始时间. Defaults to None. end_time (_type_, optional): 开人脸卡结束时间. Defaults to None. Returns: _type_: _description_ """ dh_id = ep.third_info.get('dh_id', None) dh_photo = ep.third_info.get('dh_photo', None) dh_face_card = ep.third_info.get('dh_face_card', None) departmentId = 1 if ep.belong_dept: try: departmentId = ep.belong_dept.third_info['dh_id'] except Exception: pass if ep.third_info.get('dh_id', None): # 如果有大华信息 dh_id = ep.third_info['dh_id'] dh_photo = ep.third_info['dh_photo'] json_data = { "service": "ehs", "id": dh_id, "name": ep.name, "code": ep.number if ep.number else ranstr(6), "paperType": 111, "paperNumber": ep.id_number, "paperAddress": "default", "departmentId": departmentId, "phone": ep.phone, "email": ep.email, "sex": 1 if ep.gender == '男' else 2, "biosignatureTypeList": [3], "personBiosignatures": [{ "type": 3, "index": 1, "path": dh_photo }] } if ep.photo != old_photo and ep.photo: _, res = dhClient.request(**dhapis['person_img_upload'], file_path_rela=ep.photo) dh_photo = res["fileUrl"] json_data.update( { "biosignatureTypeList": [3], "personBiosignatures": [{ "type": 3, "index": 1, "path": dh_photo }] } ) dhClient.request(**dhapis['person_update'], json=json_data) else: _, res = dhClient.request(**dhapis['person_gen_id']) dh_id = res['id'] json_data = { "service": "ehs", "id": dh_id, "name": ep.name, "code": ep.number if ep.number else ranstr(6), "paperType": 111, "paperNumber": ep.id_number, "paperAddress": "default", "departmentId": departmentId, "phone": ep.phone, "email": ep.email, "sex": 1 if ep.gender == '男' else 2 } _, res = dhClient.request(**dhapis['person_img_upload'], file_path_rela=ep.photo) dh_photo = res["fileUrl"] json_data.update( { "biosignatureTypeList": [3], "personBiosignatures": [{ "type": 3, "index": 1, "path": dh_photo }] } ) _, res = dhClient.request(**dhapis['person_add'], json=json_data) ep = cls.save(ep, data={'dh_id': dh_id, 'dh_photo': dh_photo}) # 开人脸卡 dh_face_card = cls.open_face_card( ep=ep, dh_id=dh_id, departmentId=departmentId, start_time=start_time, end_time=end_time) # 授予门禁权限 dh_dchannels = cls.door_auth(ep=ep) return {'dh_id': dh_id, 'dh_photo': dh_photo, 'dh_face_card': dh_face_card, 'dh_dchannels': dh_dchannels} @classmethod def open_face_card(cls, ep, dh_id, departmentId, start_time, end_time): """开人脸卡/有卡就更新卡时间 """ if ep.third_info.get('dh_face_card', None): cardNumber = ep.third_info.get('dh_face_card') # 如果有人脸卡就执行更新操作 if start_time is None: # 如果时间段未提供,跳过更新操作 pass else: startDate = start_time.strftime("%Y-%m-%d %H:%M:%S") endDate = 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) return cardNumber else: _, res = dhClient.request(**dhapis['card_gen_id']) cardId = res['id'] cardNumber = str(ep.id)[3:8] + rannum(5) now = datetime.now() if start_time is None: # 如果未规定时间范围, 默认50年 startDate = now.strftime("%Y-%m-%d %H:%M:%S") endDate = (datetime(year=now.year+50, month=now.month, day=1)).strftime("%Y-%m-%d %H:%M:%S") else: startDate = start_time.strftime("%Y-%m-%d %H:%M:%S") endDate = end_time.strftime("%Y-%m-%d %H:%M:%S") json_data = { "id": cardId, "cardNumber": cardNumber, "category": 0, "cardType": 0, "personId": dh_id, "departmentId": departmentId, "startDate": startDate, "endDate": endDate } _, res = dhClient.request(**dhapis['card_add'], json=json_data) time.sleep(8) # 等待确保生成卡片 cls.save(ep, data={'dh_face_card': cardNumber}) return cardNumber @classmethod def door_auth(cls, ep: Employee, dh_dchannels: list = []): """授予门禁权限 """ from apps.third.models import TDevice dh_face_card = ep.third_info.get('dh_face_card', None) if dh_dchannels: pass else: # 查找可授予的门禁通道号 dh_dchannels = list(TDevice.objects.filter(type=TDevice.DEVICE_DCHANNEL, access_list__contains=ep.type).values_list('code', flat=True)) if dh_dchannels: details = [] for i in dh_dchannels: details.append({ "privilegeType": 1, "resouceCode": i }) json_data = { "cardNumbers": [dh_face_card], "timeQuantumId": 1, "cardPrivilegeDetails": details } is_ok, res = dhClient.request(**dhapis['card_door_authority'], json=json_data, raise_exception=False) if is_ok == 'fail' and '44999999' in res['code']: time.sleep(6) dhClient.request(**dhapis['card_door_authority'], json=json_data) elif is_ok == 'fail': raise ParseError(**res) elif is_ok == 'error': raise APIException(**DH_REQUEST_ERROR) cls.save(ep, data={'dh_dchannels': dh_dchannels}) return dh_dchannels @classmethod def save(cls, ep: Employee, data: dict): """更新third_info """ ti = ep.third_info ti.update(data) ep.third_info = ti ep.save() return ep @classmethod def swipe(cls, data: dict): """ 刷卡事件/用于记录考勤 """ from apps.vm.models import Visit from apps.rpm.models import Rpj nodeCode = data['info']['nodeCode'] device = TDevice.objects.filter(code=nodeCode).first() if device: id_number = data['info']['extend'].get('paperNumber', None) if id_number: # 如果有身份证号 if device.is_clock: # 如果设置为关联考勤 # myLogger.info(data['info']['extend']) if data['info']['extend']['enterOrExit'] == 1: # 如果是进门 ep = Employee.objects.filter(id_number=id_number, type__in=["employee", "remployee"]).first() # 如果是内部/相关方员工创建上班打卡记录(更新) if ep and ep.is_atwork is False: now = timezone.now() cr_10 = ClockRecord.objects.filter( type=10, employee=ep, create_time__year=now.year, create_time__month=now.month, create_time__day=now.day).first() if cr_10: if now < cr_10.create_time: cr_10.create_time = now cr_10.trigger = 'door' cr_10.detail = data['info']['extend'] cr_10.save() else: cr_10 = ClockRecord() cr_10.type = 10 cr_10.employee = ep cr_10.trigger = 'door' cr_10.detail = data['info']['extend'] cr_10.save() ep.is_atwork = True ep.last_check_time = now ep.save() elif data['info']['extend']['enterOrExit'] == 2: # 如果是出门 id_number = data['info']['extend']['paperNumber'] if id_number: ep = Employee.objects.filter(id_number=id_number, type="employee").first() # 如果是内部/相关方员工创建下班打卡记录(更新) if ep and ep.is_atwork: now = timezone.now() cr_20 = ClockRecord.objects.filter( type=20, employee=ep, create_time__year=now.year, create_time__month=now.month, create_time__day=now.day).first() if cr_20: if now > cr_20.create_time: cr_20.create_time = now cr_20.trigger = 'door' cr_20.detail = data['info']['extend'] cr_20.save() else: cr_20 = ClockRecord() cr_20.type = 20 cr_20.employee = ep cr_20.trigger = 'door' cr_20.detail = data['info']['extend'] cr_20.save() ep.is_atwork = False ep.last_check_time = now ep.save() # 进行相关方/访客项目更新 Visit.objects.filter(state=Visit.V_ENTER, visitors__employee__id_number=id_number).update( state=Visit.V_WORKING) Rpj.objects.filter(state=Rpj.RPJ_ENTER, remployees__employee__id_number=id_number).update( state=Rpj.RPJ_WORKING) # 此处可触发安全帽事件逻辑