diff --git a/apps/hrm/errors.py b/apps/hrm/errors.py new file mode 100644 index 00000000..0b4d1e27 --- /dev/null +++ b/apps/hrm/errors.py @@ -0,0 +1 @@ +NO_NEED_LEVEL_REMARK = {"code":"no_need_level_remark", "detail":"无需填写离岗说明"} \ No newline at end of file diff --git a/apps/hrm/models.py b/apps/hrm/models.py index 25f588bd..23c55555 100644 --- a/apps/hrm/models.py +++ b/apps/hrm/models.py @@ -2,12 +2,12 @@ from django.db import models from django.db.models.query import QuerySet from apps.system.models import User -from apps.utils.models import CommonADModel, CommonAModel +from apps.utils.models import CommonADModel, CommonAModel, CommonBModel -class Employee(CommonAModel): +class Employee(CommonBModel): """ 员工信息 """ @@ -28,7 +28,7 @@ class Employee(CommonAModel): id_number = models.CharField('身份证号', max_length=100, null=True, blank=True) gender = models.CharField('性别', max_length=10, default='男') signature = models.CharField('签名图片', max_length=200, null=True, blank=True) - birthday = models.DateField('出生年月', null=True, blank=True) + birthday = models.DateField('出生年月日', null=True, blank=True) qualification = models.CharField('学历', max_length=50, null=True, blank=True) job_state = models.IntegerField('在职状态', choices=jobstate_choices, default=1) face_data = models.JSONField('人脸识别数据', null=True, blank=True) diff --git a/apps/hrm/serializers.py b/apps/hrm/serializers.py index 1ebc9237..681556e3 100644 --- a/apps/hrm/serializers.py +++ b/apps/hrm/serializers.py @@ -2,13 +2,13 @@ from apps.system.models import User from rest_framework.serializers import ModelSerializer from rest_framework import serializers -from utils.mixins import DynamicFieldsSerializerMixin -from .models import ClockRecord, Employee, NotWorkRemark -from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer +from apps.utils.serializers import CustomModelSerializer -class EmployeeSerializer(DynamicFieldsSerializerMixin, ModelSerializer): - name = serializers.CharField(source='user.name', read_only=True) - dept_ = OrganizationSimpleSerializer(source='user.dept', read_only=True) +from .models import ClockRecord, Employee, NotWorkRemark +from apps.system.serializers import DeptSimpleSerializer,UserSimpleSerializer + +class EmployeeSerializer(CustomModelSerializer): + belong_dept_ = DeptSimpleSerializer(source='user.belong_dept', read_only=True) class Meta: model = Employee exclude = ['face_data'] @@ -17,13 +17,6 @@ class EmployeeNotWorkRemarkSerializer(ModelSerializer): class Meta: model = Employee fields = ['not_work_remark'] - -class FaceLoginSerializer(serializers.Serializer): - base64 = serializers.CharField() - - -class FaceClockCreateSerializer(serializers.Serializer): - base64 = serializers.CharField() class ClockRecordListSerializer(serializers.ModelSerializer): create_by_ = UserSimpleSerializer(source='create_by', read_only=True) diff --git a/apps/hrm/services.py b/apps/hrm/services.py deleted file mode 100644 index eca4639e..00000000 --- a/apps/hrm/services.py +++ /dev/null @@ -1,50 +0,0 @@ -from django.conf import settings -import uuid -import face_recognition -import os -from apps.hrm.models import Employee -from apps.hrm.tasks import update_all_user_facedata_cache -from apps.system.models import User -from django.core.cache import cache - -class HRMService: - - @classmethod - def face_compare_from_base64(cls, base64_data): - filename = str(uuid.uuid4()) - filepath = settings.BASE_DIR +'/temp/' + 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] - os.remove(filepath) - except: - os.remove(filepath) - return None, '识别失败,请调整位置' - - # 匹配人脸库 - face_datas = cache.get('face_datas') - if face_datas is None: - update_all_user_facedata_cache() - face_datas = cache.get('face_datas') - face_users = cache.get('face_users') - results = face_recognition.compare_faces(face_datas, - unknown_face_encoding, tolerance=0.45) - for index, value in enumerate(results): - if value: - # 识别成功 - user = User.objects.get(id=face_users[index]) - return user, '' - return None, '人脸未匹配,请调整位置' - - @classmethod - def get_facedata_from_img(cls, img_path): - try: - photo_path = settings.BASE_DIR + img_path - picture_of_me = face_recognition.load_image_file(photo_path) - 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, '人脸数据获取失败请重新上传图片' \ No newline at end of file diff --git a/apps/hrm/tasks.py b/apps/hrm/tasks.py index b365f58f..4fb60923 100644 --- a/apps/hrm/tasks.py +++ b/apps/hrm/tasks.py @@ -2,7 +2,6 @@ from __future__ import absolute_import, unicode_literals from celery import shared_task from apps.hrm.models import Employee -from django.core.cache import cache @shared_task @@ -12,19 +11,4 @@ def update_all_employee_not_atwork(): """ Employee.objects.all().update(is_atwork=False, last_check_time = None, not_work_remark=None) -@shared_task -def update_all_user_facedata_cache(): - """ - 更新人脸数据缓存 - """ - facedata_queyset = Employee.objects.filter(face_data__isnull=False, - user__is_active=True).values('user', 'face_data') - face_users = [] - face_datas = [] - for i in facedata_queyset: - face_users.append(i['user']) - face_datas.append(i['face_data']) - cache.set('face_users', face_users, timeout=None) - cache.set('face_datas', face_datas, timeout=None) - \ No newline at end of file diff --git a/apps/hrm/views.py b/apps/hrm/views.py index bca0b796..70abf050 100644 --- a/apps/hrm/views.py +++ b/apps/hrm/views.py @@ -1,12 +1,9 @@ from django.shortcuts import render from django.utils import timezone from rest_framework.response import Response -from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.mixins import UpdateModelMixin, RetrieveModelMixin, CreateModelMixin, ListModelMixin +from apps.hrm.errors import NO_NEED_LEVEL_REMARK from apps.hrm.filters import ClockRecordFilterSet, EmployeeFilterSet, NotWorkRemarkFilterSet -from apps.hrm.services import HRMService -from apps.hrm.tasks import update_all_user_facedata_cache -from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.hrm.models import ClockRecord, Employee, NotWorkRemark from apps.hrm.serializers import ClockRecordListSerializer, EmployeeNotWorkRemarkSerializer, EmployeeSerializer, FaceClockCreateSerializer, FaceLoginSerializer, NotWorkRemarkListSerializer @@ -20,18 +17,20 @@ from apps.system.models import User from apps.system.serializers import UserSimpleSerializer from rest_framework.permissions import AllowAny from rest_framework.decorators import action +from apps.utils.viewsets import CustomModelViewSet, CustomGenericViewSet +from rest_framework.exceptions import ParseError # Create your views here. -class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMixin, ListModelMixin, RetrieveModelMixin, GenericViewSet): +class EmployeeViewSet(CustomModelViewSet): """ - 员工详细信息 + 员工信息管理 """ - perms_map = {'get': '*', 'put': 'employee_update'} queryset = Employee.objects.all() + select_related_fields = ['user'] filterset_class = EmployeeFilterSet serializer_class = EmployeeSerializer - search_fields = ['user__name', 'number', 'user__username'] + search_fields = ['name', 'number', 'user__username'] ordering = ['-pk'] def update(self, request, *args, **kwargs): @@ -81,107 +80,30 @@ class EmployeeViewSet(CreateUpdateModelAMixin, OptimizationMixin, UpdateModelMix instance.update_by = request.user instance.save() return Response() - return Response('无需填写离岗说明', status=status.HTTP_400_BAD_REQUEST) + raise ParseError(**NO_NEED_LEVEL_REMARK) -class ClockRecordViewSet(CreateModelMixin, ListModelMixin, GenericViewSet): +class ClockRecordViewSet(ListModelMixin, CustomGenericViewSet): """ 打卡记录 """ perms_map = {'get':'*', 'post':'*'} authentication_classes = [] permission_classes = [AllowAny] - queryset = ClockRecord.objects.select_related('create_by').all() + queryset = ClockRecord.objects.all() + select_related_fields = ['create_by'] serializer_class = ClockRecordListSerializer filterset_class = ClockRecordFilterSet ordering = ['-pk'] - - def get_serializer_class(self): - if self.action == 'create': - return FaceClockCreateSerializer - return super().get_serializer_class() - - def create(self, request, *args, **kwargs): - now = timezone.now() - now_local = timezone.localtime() - if 8<=now_local.hour<=17: - base64_data = base64.urlsafe_b64decode(tran64( - request.data.get('base64').replace(' ', '+'))) - user, msg = HRMService.face_compare_from_base64(base64_data) - if user: - ins, created = ClockRecord.objects.get_or_create( - create_by = user, create_time__hour__range = [8,18], - create_time__year=now_local.year, create_time__month=now_local.month, - create_time__day=now_local.day, - defaults={ - 'type':ClockRecord.ClOCK_WORK1, - 'create_by':user, - 'create_time':now - }) - if not created: - ins.update_time = now - ins.save() - # 设为在岗 - Employee.objects.filter(user=user).update(is_atwork=True, last_check_time=now) - return Response(UserSimpleSerializer(instance=user).data) - return Response(msg, status=status.HTTP_400_BAD_REQUEST) - return Response('非打卡时间范围', status=status.HTTP_400_BAD_REQUEST) -class NotWorkRemarkViewSet(ListModelMixin, GenericViewSet): +class NotWorkRemarkViewSet(ListModelMixin, CustomGenericViewSet): """ 离岗说明 """ perms_map = {'get':'*'} - queryset = NotWorkRemark.objects.select_related('user').all() + queryset = NotWorkRemark.objects.all() + select_related_fields = ['user'] serializer_class = NotWorkRemarkListSerializer filterset_class = NotWorkRemarkFilterSet - ordering = ['-pk'] - - -import base64 - -def tran64(s): - missing_padding = len(s) % 4 - if missing_padding != 0: - s = s+'='* (4 - missing_padding) - return s - -class FaceLogin(CreateAPIView): - authentication_classes = [] - permission_classes = [] - serializer_class = FaceLoginSerializer - - - def create(self, request, *args, **kwargs): - """ - 人脸识别登录 - """ - base64_data = base64.urlsafe_b64decode(tran64(request.data.get('base64').replace(' ', '+'))) - user, msg = HRMService.face_compare_from_base64(base64_data) - if user: - refresh = RefreshToken.for_user(user) - # 可设为在岗 - now = timezone.now() - now_local = timezone.localtime() - if 8<=now_local.hour<=17: - ins, created = ClockRecord.objects.get_or_create( - create_by = user, create_time__hour__range = [8,18], - create_time__year=now_local.year, create_time__month=now_local.month, - create_time__day=now_local.day, - defaults={ - 'type':ClockRecord.ClOCK_WORK1, - 'create_by':user, - 'create_time':now - }) - # 设为在岗 - if created: - Employee.objects.filter(user=user).update(is_atwork=True, last_check_time=now) - - return Response({ - 'refresh': str(refresh), - 'access': str(refresh.access_token), - 'username':user.username, - 'name':user.name - }) - return Response(msg, status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file + ordering = ['-pk'] \ No newline at end of file diff --git a/apps/system/serializers.py b/apps/system/serializers.py index b3608238..61afd73f 100644 --- a/apps/system/serializers.py +++ b/apps/system/serializers.py @@ -12,6 +12,7 @@ from rest_framework.exceptions import ParseError, APIException from django.db import transaction from apps.third.tapis import dhapis from rest_framework.validators import UniqueValidator +from django.contrib.auth.hashers import make_password class IntervalSerializer(CustomModelSerializer): class Meta: @@ -273,6 +274,7 @@ class UserCreateSerializer(CustomModelSerializer): class Meta: model = User fields = ['username', 'name', 'avatar', 'is_active'] + class PasswordChangeSerializer(serializers.Serializer): diff --git a/apps/system/views.py b/apps/system/views.py index 52370ac5..74b480bb 100644 --- a/apps/system/views.py +++ b/apps/system/views.py @@ -305,14 +305,10 @@ class UserViewSet(CustomModelViewSet): 创建用户 """ - password = request.data.get('password', None) - if password: - password = make_password(password) - else: - password = make_password('0000') + password = make_password('0000') serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) - serializer.save(password=password) + serializer.save(password=password, belong_dept=None) return Response(data=serializer.data) @action(methods=['put'], detail=False, diff --git a/apps/utils/serializers.py b/apps/utils/serializers.py index 48e7238d..7beae265 100644 --- a/apps/utils/serializers.py +++ b/apps/utils/serializers.py @@ -19,7 +19,9 @@ class CustomModelSerializer(DynamicFieldsMixin, serializers.ModelSerializer): if self.request: if getattr(self.request, 'user', None): validated_data['create_by'] = self.request.user - if getattr(self.request.user, 'belong_dept', None): + if 'belong_dept' in validated_data: # 如果指定数据归属部门 + pass + elif getattr(self.request.user, 'belong_dept', None): validated_data['belong_dept'] = self.request.user.belong_dept return super().create(validated_data)