feat: hrm-新增人员岗位调动

This commit is contained in:
TianyangZhang 2026-01-26 11:00:19 +08:00
parent 65cdeb0e7c
commit c9089eeb27
7 changed files with 145 additions and 8 deletions

View File

@ -0,0 +1,46 @@
# Generated by Django 3.2.12 on 2026-01-23 08:03
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 = [
('wf', '0006_auto_20251215_1645'),
('system', '0006_auto_20241213_1249'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('hrm', '0025_leave'),
]
operations = [
migrations.CreateModel(
name='EmployeeTransfer',
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='删除标记')),
('is_change', models.BooleanField(default=False, verbose_name='是否跨部门调动')),
('is_promotion', models.BooleanField(default=False, verbose_name='是否晋升')),
('transfer_date', models.DateField(verbose_name='调岗日期')),
('original_slary', models.PositiveIntegerField(blank=True, null=True, verbose_name='原岗位薪资')),
('new_slary', models.PositiveIntegerField(blank=True, null=True, verbose_name='调岗后薪资')),
('content', models.TextField(blank=True, null=True, verbose_name='个人工作内容')),
('reason', models.TextField(blank=True, null=True, verbose_name='调动原因')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='employeetransfer_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hrm.employee', verbose_name='员工')),
('new_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='transfer_new_dept', to='system.dept', verbose_name='新部门')),
('new_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='transfer_new_post', to='system.post', verbose_name='新岗位')),
('original_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='transfer_original_dept', to='system.dept', verbose_name='原部门')),
('original_post', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='transfer_original_post', to='system.post', verbose_name='原岗位')),
('ticket', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='transfer_ticket', to='wf.ticket', verbose_name='关联工单')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='employeetransfer_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.12 on 2026-01-23 08:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('hrm', '0026_employeetransfer'),
]
operations = [
migrations.AlterField(
model_name='leave',
name='leave_type',
field=models.PositiveSmallIntegerField(choices=[(10, '事假'), (20, '病假'), (30, '婚假'), (40, '丧假'), (50, '公假'), (60, '工伤'), (70, '产假'), (80, '护理假'), (90, '其他')], default=10, verbose_name='请假类型'),
),
]

View File

@ -265,9 +265,29 @@ class Leave(CommonADModel):
employee = models.ForeignKey(Employee, verbose_name='员工', on_delete=models.CASCADE)
start_date = models.DateTimeField('开始日期')
end_date = models.DateTimeField('结束日期')
leave_type = models.PositiveSmallIntegerField('请假类型', choices=E_TYPE_CHOISE, null=True, blank=True)
leave_type = models.PositiveSmallIntegerField('请假类型', choices=E_TYPE_CHOISE, default=10)
reason = models.TextField('请假事由')
hour = models.PositiveSmallIntegerField('请假时长', null=True, blank=True)
file = models.TextField('证明', null=True, blank=True)
ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单',
on_delete=models.CASCADE, related_name='leave_ticket', null=True, blank=True)
on_delete=models.CASCADE, related_name='leave_ticket', null=True, blank=True)
class EmployeeTransfer(CommonADModel):
"""
TN:员工岗位调动
"""
employee = models.ForeignKey(Employee, verbose_name='员工', on_delete=models.CASCADE)
is_change = models.BooleanField('是否跨部门调动', default=False)
is_promotion = models.BooleanField('是否晋升', default=False)
new_dept = models.ForeignKey('system.Dept', verbose_name='新部门', related_name="transfer_new_dept", on_delete=models.CASCADE, null=True, blank=True)
new_post = models.ForeignKey('system.Post', verbose_name='新岗位', related_name="transfer_new_post", on_delete=models.CASCADE, null=True, blank=True)
original_dept = models.ForeignKey('system.Dept', verbose_name='原部门', related_name="transfer_original_dept", on_delete=models.CASCADE, null=True, blank=True)
original_post = models.ForeignKey('system.Post', verbose_name='原岗位', related_name="transfer_original_post", on_delete=models.CASCADE, null=True, blank=True)
transfer_date = models.DateField('调岗日期')
original_slary = models.PositiveIntegerField('原岗位薪资', null=True, blank=True)
new_slary = models.PositiveIntegerField('调岗后薪资', null=True, blank=True)
content = models.TextField('个人工作内容', null=True, blank=True)
reason = models.TextField('调动原因', null=True, blank=True)
ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单',
on_delete=models.CASCADE, related_name='transfer_ticket', null=True, blank=True)

View File

@ -9,7 +9,7 @@ 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)
NotWorkRemark, Attendance, Resignation, EmpNeed, EmpJoin, EmpPersonInfo, Leave, EmployeeTransfer)
from apps.system.serializers import DeptSimpleSerializer, UserSimpleSerializer
from django.db import transaction
from django.core.cache import cache
@ -377,3 +377,21 @@ class LeaveSerializer(CustomModelSerializer):
model = Leave
fields = '__all__'
class TransferSerializer(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 = EmployeeTransfer
fields = '__all__'
def create(self, validated_data):
is_change = validated_data['is_change']
if is_change:
if validated_data['new_dept'] == validated_data['original_dept']:
raise ParseError('新旧部门相同,无需调动')
elif validated_data['new_post'] == validated_data['original_post']:
raise ParseError('新旧岗位相同,无需调动')
else:
return super().create(validated_data)

View File

@ -11,7 +11,8 @@ 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, Resignation
from apps.hrm.models import ClockRecord, Employee, Resignation, EmployeeTransfer
from apps.system.models import UserPost
from apps.third.dahua import dhClient
from apps.third.models import TDevice
from apps.third.tapis import dhapis
@ -497,4 +498,21 @@ class HrmService:
print(f'{ep.name}-办公室打卡权限已删除')
# 人员调岗申请
def post_transfer(ticket: Ticket, transitons, new_ticket_data:dict):
try:
obj = EmployeeTransfer.objects.get(id=new_ticket_data['t_id'])
except EmployeeTransfer.DoesNotExist:
raise ParseError('调岗申请不存在')
data_save = {k: v for k, v in new_ticket_data.items() if k not in ['t_model', 't_id']}
# 需要删除UserPost中的记录然后新增一条调到的部门和岗位记录排序为1
try:
UserPost.objects.filter(post=obj.original_post, dept=obj.original_dept, user=obj.employee.user).delete()
except UserPost.DoesNotExist:
raise ParseError('原岗位记录不存在')
UserPost.objects.create(post=obj.new_post, dept=obj.new_dept, user=obj.employee.user, sort=1)
# 如果有调薪并有领导申请觉得那么可以从new_ticket_data 获取调薪金额
for k, v in data_save.items():
setattr(obj, k, v)
obj.save()

View File

@ -1,5 +1,5 @@
from apps.hrm.views import (CertificateViewSet, ClockRecordViewSet, EmployeeViewSet, NotWorkRemarkViewSet, EmpNeedViewSet,
AttendanceViewSet, ResignationViewSet, EmpJoinViewSet, LeaveViewSet)
AttendanceViewSet, ResignationViewSet, EmpJoinViewSet, LeaveViewSet, TransferViewSet)
from django.urls import path, include
from rest_framework.routers import DefaultRouter
@ -17,6 +17,7 @@ router.register('resignation', ResignationViewSet, basename='resignation')
router.register('empneed', EmpNeedViewSet, basename='empneed')
router.register('empjoin', EmpJoinViewSet, basename='empjoin')
router.register('leave', LeaveViewSet, basename='leave')
router.register('transfer', TransferViewSet, basename='transfer')
urlpatterns = [
path(API_BASE_URL, include(router.urls)),
]

View File

@ -12,7 +12,7 @@ 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, Resignation, EmpNeed, EmpJoin, Leave
from apps.hrm.models import Certificate, ClockRecord, Employee, NotWorkRemark, Attendance, Resignation, EmpNeed, EmpJoin, Leave, EmployeeTransfer
from apps.hrm.serializers import (CertificateCreateUpdateSerializer, CertificateSerializer, ChannelAuthoritySerializer, EmpJoinSerializer,
ClockRecordListSerializer,
EmployeeCreateUpdateSerializer, EmployeeDetailSerializer, EmployeeImproveSerializer,
@ -20,7 +20,7 @@ from apps.hrm.serializers import (CertificateCreateUpdateSerializer, Certificate
EmployeeSerializer,
ClockRecordSimpleSerializer, ClockRecordCreateSerializer,
NotWorkRemarkListSerializer, CorrectSerializer, AttendanceSerializer,
ResignationSerializer, EmpNeedSerializer, LeaveSerializer)
ResignationSerializer, EmpNeedSerializer, LeaveSerializer, TransferSerializer)
from apps.hrm.services import HrmService
from apps.third.dahua import dhClient
@ -468,4 +468,20 @@ class LeaveViewSet(TicketMixin, EuModelViewSet):
workflow_key = "wf_leave"
def gen_other_ticket_data(self, instance):
return {"hour": instance.hour if instance.hour else None}
return {"hour": instance.hour if instance.hour else None}
class TransferViewSet(TicketMixin, EuModelViewSet):
select_related_fields = [
'employee',
'employee__belong_dept',
'employee__post',
'ticket',
]
queryset = EmployeeTransfer.objects.all()
serializer_class = TransferSerializer
filterset_fields = ['employee__belong_dept']
search_fields = ["employee__name", "employee__post", "employee__belong_dept"]
workflow_key = "wf_transfer"
def gen_other_ticket_data(self, instance):
return {"name": instance.employee.name if instance.employee.name else None}