diff --git a/apps/hrm/migrations/0020_auto_20251106_0942.py b/apps/hrm/migrations/0020_auto_20251106_0942.py new file mode 100644 index 00000000..b6dff38f --- /dev/null +++ b/apps/hrm/migrations/0020_auto_20251106_0942.py @@ -0,0 +1,47 @@ +# Generated by Django 3.2.12 on 2025-11-06 01:42 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('wf', '0004_workflow_view_path2'), + ('hrm', '0019_certificate_state'), + ] + + operations = [ + migrations.AddField( + model_name='employee', + name='end_date', + field=models.DateField(blank=True, null=True, verbose_name='离职日期'), + ), + migrations.AddField( + model_name='employee', + name='start_date', + field=models.DateField(blank=True, null=True, verbose_name='入职日期'), + ), + migrations.CreateModel( + name='Resignation', + 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='删除标记')), + ('end_date', models.DateField(verbose_name='离职日期')), + ('reason', models.TextField(verbose_name='离职原因')), + ('handle_date', models.DateField(blank=True, null=True, verbose_name='办理离职交接日期')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='resignation_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hrm.employee', verbose_name='员工')), + ('ticket', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wf.ticket', verbose_name='关联工单')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='resignation_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/hrm/models.py b/apps/hrm/models.py index bcea7f76..2802b21d 100755 --- a/apps/hrm/models.py +++ b/apps/hrm/models.py @@ -55,6 +55,8 @@ class Employee(CommonBModel): on_delete=models.SET_NULL, null=True, blank=True) face_data = models.JSONField( '人脸数据', null=True, blank=True) # 存储的是字典(模型名:人脸数据) + start_date = models.DateField('入职日期', null=True, blank=True) + end_date = models.DateField('离职日期', null=True, blank=True) class Meta: verbose_name = '员工补充信息' @@ -189,4 +191,15 @@ class Certificate(CommonAModel): if need_update and new_state != self.state: self.state = new_state self.save(update_fields=['state']) - return new_state \ No newline at end of file + return new_state + + +class Resignation(CommonADModel): + """ + TN:离职记录 + """ + employee = models.ForeignKey(Employee, verbose_name='员工', on_delete=models.CASCADE) + end_date = models.DateField('离职日期') + reason = models.TextField('离职原因') + handle_date = models.DateField('办理离职交接日期', null=True, blank=True) + ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.SET_NULL, null=True, blank=True) \ No newline at end of file diff --git a/apps/hrm/serializers.py b/apps/hrm/serializers.py index d76994b5..79139a54 100755 --- a/apps/hrm/serializers.py +++ b/apps/hrm/serializers.py @@ -8,7 +8,8 @@ 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 +from apps.hrm.models import (Certificate, ClockRecord, Employee, + NotWorkRemark, Attendance, Resignation) from apps.system.serializers import DeptSimpleSerializer, UserSimpleSerializer from django.db import transaction from django.core.cache import cache @@ -313,3 +314,11 @@ class AttendanceSerializer(CustomModelSerializer): 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) + class Meta: + model = Resignation + fields = '__all__' \ No newline at end of file diff --git a/apps/hrm/services.py b/apps/hrm/services.py index 01261e02..5488e3b5 100755 --- a/apps/hrm/services.py +++ b/apps/hrm/services.py @@ -8,14 +8,16 @@ from dateutil import tz from django.conf import settings from django.utils import timezone from django.core.cache import cache +from rest_framework.exceptions import ParseError from apps.system.models import User -from apps.hrm.models import ClockRecord, Employee +from apps.hrm.models import ClockRecord, Employee, Resignation from apps.third.dahua import dhClient from apps.third.models import TDevice from apps.third.tapis import dhapis from apps.utils.tools import rannum, ranstr import numpy as np +from apps.wf.models import Ticket, Transition myLogger = logging.getLogger('log') @@ -493,3 +495,12 @@ class HrmService: dhClient.request( **dhapis['card_door_authority_delete'], json=rdict) print(f'{ep.name}-办公室打卡权限已删除') + + + +def bind_resignation(ticket: Ticket, transition: Transition, new_ticket_data: dict): + ins = Resignation.objects.get(id=new_ticket_data['rpj']) + if ins.ticket and ins.ticket.id != ticket.id: + raise ParseError('重复创建工单') + ticket.create_by = ins.create_by + ticket.save() \ No newline at end of file diff --git a/apps/hrm/urls.py b/apps/hrm/urls.py index a31829a6..e91bfbc4 100755 --- a/apps/hrm/urls.py +++ b/apps/hrm/urls.py @@ -1,4 +1,5 @@ -from apps.hrm.views import CertificateViewSet, ClockRecordViewSet, EmployeeViewSet, NotWorkRemarkViewSet, AttendanceViewSet +from apps.hrm.views import (CertificateViewSet, ClockRecordViewSet, EmployeeViewSet, NotWorkRemarkViewSet, + AttendanceViewSet, ResignationViewSet) from django.urls import path, include from rest_framework.routers import DefaultRouter @@ -12,6 +13,7 @@ router.register('not_work_remark', NotWorkRemarkViewSet, basename='not_work_reamrk') router.register('certificate', CertificateViewSet, basename='certificate') router.register('attendance', AttendanceViewSet, basename='attendance') +router.register('resignation', ResignationViewSet, basename='resignation') urlpatterns = [ path(API_BASE_URL, include(router.urls)), ] diff --git a/apps/hrm/views.py b/apps/hrm/views.py index 68a60cac..903ab22b 100755 --- a/apps/hrm/views.py +++ b/apps/hrm/views.py @@ -12,21 +12,22 @@ from rest_framework.response import Response from apps.hrm.errors import NO_NEED_LEVEL_REMARK from apps.hrm.filters import (CertificateFilterSet, ClockRecordFilterSet, EmployeeFilterSet, NotWorkRemarkFilterSet) -from apps.hrm.models import Certificate, ClockRecord, Employee, NotWorkRemark, Attendance +from apps.hrm.models import Certificate, ClockRecord, Employee, NotWorkRemark, Attendance, Resignation from apps.hrm.serializers import (CertificateCreateUpdateSerializer, CertificateSerializer, ChannelAuthoritySerializer, ClockRecordListSerializer, EmployeeCreateUpdateSerializer, EmployeeDetailSerializer, EmployeeImproveSerializer, EmployeeNotWorkRemarkSerializer, EmployeeSerializer, ClockRecordSimpleSerializer, ClockRecordCreateSerializer, - NotWorkRemarkListSerializer, CorrectSerializer, AttendanceSerializer) + NotWorkRemarkListSerializer, CorrectSerializer, AttendanceSerializer, + ResignationSerializer) from apps.hrm.services import HrmService from apps.third.dahua import dhClient from apps.third.tapis import dhapis from apps.utils.export import export_excel from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet -from apps.utils.mixins import BulkCreateModelMixin, BulkDestroyModelMixin +from apps.utils.mixins import BulkCreateModelMixin, BulkDestroyModelMixin, CustomListModelMixin epTypeOptions = {'employee': '正式员工', 'remployee': '相关方', 'visitor': '访客', 'driver': '货车司机'} @@ -389,4 +390,12 @@ class CertificateViewSet(CustomModelViewSet): def perform_update(self, serializer): ins: Certificate = serializer.save() - ins.get_state(need_update=True) \ No newline at end of file + ins.get_state(need_update=True) + + +class ResignationViewSet(CustomListModelMixin, BulkCreateModelMixin, CustomGenericViewSet): + perms_map = {"get": "*", "post": "resignation.create"} + select_related_fields = ['employee', 'employee__belong_dept', 'employee__post'] + queryset = Resignation.objects.all() + serializer_class = ResignationSerializer + search_fields = ["employee__name"] \ No newline at end of file