from datetime import timedelta from rest_framework.serializers import ModelSerializer from rest_framework import serializers from apps.hrm.services import HrmService from apps.utils.fields import MyFilePathField from django.utils import timezone from apps.utils.serializers import CustomModelSerializer from apps.utils.constants import EXCLUDE_FIELDS from apps.hrm.models import (Certificate, ClockRecord, Employee, NotWorkRemark, Attendance, Resignation, EmpNeed, EmpJoin, EmpPersonInfo, Leave) from apps.system.serializers import DeptSimpleSerializer, UserSimpleSerializer from django.db import transaction from django.core.cache import cache from apps.utils.tools import check_id_number_strict, get_info_from_id from rest_framework.exceptions import ParseError from django.conf import settings import datetime from apps.wf.serializers import TicketSimpleSerializer 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', 'type'] class EmployeeSimpleSerializer(CustomModelSerializer): 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'] def get_location(self, obj): key_str = 'ep_{}'.format(obj.id) return cache.get(key_str, None) # class EmployeeBaseSerializer(CustomModelSerializer): # def save(self, **kwargs): # if self.validated_data.get('user', None): # user = self.validated_data['user'] # self.validated_data['name'] = user.name # self.validated_data['belong_dept'] = user.belong_dept # return super().save(**kwargs) class EmployeeCreateUpdateSerializer(CustomModelSerializer): id_number = serializers.CharField( label="身份证号", validators=[check_id_number_strict]) class Meta: model = Employee exclude = EXCLUDE_FIELDS + ['is_atwork', 'last_check_time', 'not_work_remark', 'third_info', 'type', 'phone', 'belong_dept', 'post', 'user'] extra_kwargs = { 'number': {'required': True}, 'photo': {'required': True}, 'id_number': {'required': True}, } @transaction.atomic def create(self, validated_data): instance = super().create(validated_data) if instance.type == 'employee': # 如果是内部员工 HrmService.sync_dahua_employee(ep=instance) return instance def update(self, instance, validated_data): id_number = validated_data['id_number'] ret = get_info_from_id(id_number) validated_data['gender'] = ret['gender'] old_photo = instance.photo old_job_state = instance.job_state old_name = instance.name 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) in_face_data = instance.face_data if face_data: if isinstance(in_face_data, dict): in_face_data['dlib'] = face_data instance.face_data = in_face_data instance.save() else: instance.face_data = {'dlib': face_data} instance.save() else: raise ParseError(msg) from apps.hrm.tasks import update_all_facedata_cache update_all_facedata_cache.delay() if instance.user and instance != old_name: instance.user.name = instance.name instance.user.save() if instance.type == 'remployee': # 如果是相关方 from apps.rpm.services import sync_to_rep sync_to_rep(instance) elif instance.type in ['visitor', 'driver']: # 如果是访客或司机 from apps.vm.services import sync_to_visitor sync_to_visitor(instance) if instance.job_state in [20, 30] and instance.user: # 如果离职了删除账户 instance.user.is_deleted = True instance.user.save() # 同时去除门禁授权 # 如果是正式员工或相关方且有门禁权限: now = timezone.now() 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': 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': 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) return instance class EmployeeImproveSerializer(CustomModelSerializer): photo_f = MyFilePathField(source='photo', read_only=True) signature_f = MyFilePathField(source='signature', read_only=True) class Meta: model = Employee fields = ['photo', 'id_number', 'email', 'gender', 'signature', 'photo_f', 'signature_f', 'phone'] extra_kwargs = { 'number': {'required': True}, 'photo': {'required': True}, 'id_number': {'required': True}, } def update(self, instance, validated_data): id_number = validated_data['id_number'] ret = get_info_from_id(id_number) validated_data['gender'] = ret['gender'] return super().update(instance, validated_data) class ChannelAuthoritySerializer(serializers.Serializer): # pks = serializers.ListField(child=serializers.CharField(max_length=20), label="员工ID列表") start_time = serializers.DateTimeField(label="开始时间") end_time = serializers.DateTimeField(label="结束时间") 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) post_name = serializers.CharField(source='post.name', read_only=True) blt_ = serializers.SerializerMethodField() photo_f = MyFilePathField(source='photo', read_only=True) signature_f = MyFilePathField(source='signature', read_only=True) class Meta: model = Employee fields = '__all__' read_only_fields = ['is_atwork', 'last_check_time', 'not_work_remark'] def get_blt_(self, obj): if hasattr(obj, 'blt'): from apps.third.serializers import TDeviceSimpleSerializer return TDeviceSimpleSerializer(instance=obj.blt).data # if hasattr(obj, 'tdevice'): # from apps.third.serializers import TDeviceSimpleSerializer # return TDeviceSimpleSerializer(instance=obj.tdevice).data return class EmployeeDetailSerializer(EmployeeSerializer): # door_range = serializers.SerializerMethodField() location = serializers.SerializerMethodField() # def get_door_range(self, obj): # third_info = obj.third_info # dh_face_card = third_info.get('dh_face_card', None) # if dh_face_card: # _, res = dhClient.request(**dhapis['card_detail'], params={'cardNumber': dh_face_card}) # return [res['startDate'], res['endDate']] def get_location(self, obj): key_str = 'ep_{}'.format(obj.id) return cache.get(key_str, None) class EmployeeNotWorkRemarkSerializer(ModelSerializer): class Meta: model = Employee fields = ['not_work_remark'] class ClockRecordListSerializer(serializers.ModelSerializer): employee_ = EmployeeSimpleSerializer(source='employee', read_only=True) class Meta: model = ClockRecord fields = '__all__' class ClockRecordCreateSerializer(serializers.ModelSerializer): clock_time = serializers.DateTimeField(label='打卡时间', required=True) class Meta: model = ClockRecord fields = ['id', 'type', 'employee', 'clock_time'] def validate(self, attrs): attrs['trigger'] = 'manual' return attrs class ClockRecordSimpleSerializer(serializers.ModelSerializer): class Meta: model = ClockRecord fields = ['id', 'type', 'exception_type', 'detail'] class NotWorkRemarkListSerializer(serializers.ModelSerializer): class Meta: model = NotWorkRemark fields = '__all__' class CertificateCreateUpdateSerializer(CustomModelSerializer): file_f = MyFilePathField(source='file', read_only=True) class Meta: model = Certificate exclude = EXCLUDE_FIELDS class CertificateSerializer(CustomModelSerializer): employee_name = serializers.CharField( source='employee.name', read_only=True) file_f = MyFilePathField(source='file', read_only=True) class Meta: model = Certificate fields = '__all__' class CorrectSerializer(serializers.Serializer): start_time = serializers.DateTimeField() end_time = serializers.DateTimeField() class AttendanceSerializer(CustomModelSerializer): user_name = serializers.CharField( source='user.name', read_only=True) belong_dept_name = serializers.CharField( source='user.belong_dept.name', read_only=True) shift_name = serializers.CharField(source='shift.name', read_only=True) post_name = serializers.CharField( source='user.post.name', read_only=True) team_name = serializers.CharField(source='team.name', read_only=True) work_time_start = serializers.DateTimeField(read_only=True) work_time_end = serializers.DateTimeField(read_only=True) class Meta: model = Attendance fields = '__all__' extra_kwargs = {'team': {'required': True}, 'post': {'required': True}} def create(self, validated_data): user = validated_data['user'] shift = validated_data['shift'] work_date = validated_data['work_date'] att = Attendance.objects.filter( user=user, work_date=work_date, shift=shift).first() if att: att.note = validated_data.get('note', '') att.state = validated_data['state'] att.update_by = self.context['request'].user att.save() return att else: start_time_o = shift.start_time_o end_time_o = shift.end_time_o if end_time_o >= start_time_o: validated_data['work_time_start'] = datetime.datetime.combine( work_date, start_time_o) validated_data['work_time_end'] = datetime.datetime.combine( work_date, end_time_o) else: validated_data['work_time_start'] = datetime.datetime.combine( work_date, start_time_o) - datetime.timedelta(days=1) validated_data['work_time_end'] = datetime.datetime.combine( work_date, end_time_o) return super().create(validated_data) def update(self, instance, validated_data): new_data = {} new_data['note'] = validated_data.get('note', '') new_data['state'] = validated_data['state'] return super().update(instance, validated_data) class ResignationSerializer(CustomModelSerializer): belong_dept_name = serializers.CharField(source="employee.belong_dept.name", read_only=True) post_name = serializers.CharField(source="employee.post.name", read_only=True) ticket_ = TicketSimpleSerializer(source="ticket", read_only=True) employee_name = serializers.CharField(source="employee.name", read_only=True) employee_id_number = serializers.CharField(source="employee.id_number", read_only=True) class Meta: model = Resignation fields = '__all__' def update(self, instance, validated_data): validated_data.pop('employee') return super().update(instance, validated_data) def create(self, validated_data): employee:Employee = validated_data['employee'] if employee.job_state == Employee.JOB_ON: pass else: raise ParseError('员工不在职,不可创建申请') if Resignation.objects.filter(employee=employee).exists(): raise ParseError('该员工已存在离职申请') return super().create(validated_data) class EmpNeedSerializer(CustomModelSerializer): dept_need_name = serializers.CharField(source='dept_need.name', read_only=True) ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) class Meta: model = EmpNeed fields = '__all__' class EmpJoinSerializer(CustomModelSerializer): ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) dept_name = serializers.CharField(source='dept_need.name', read_only=True) class Meta: model = EmpJoin fields = '__all__' class EmpPersonInfoSerializer(CustomModelSerializer): class Meta: model = EmpPersonInfo fields = ( 'name', 'gender', 'IDcard', 'phone', 'post', 'note', ) class LeaveSerializer(CustomModelSerializer): ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) employee_name = serializers.CharField(source='employee.name', read_only=True) post_name = serializers.CharField(source="employee.post.name", read_only=True) belong_dept_name = serializers.CharField(source='employee.belong_dept.name', read_only=True) class Meta: model = Leave fields = '__all__'