From c9089eeb2712066f5bf54ded8ebd8097bd43470d Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Mon, 26 Jan 2026 11:00:19 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20hrm-=E6=96=B0=E5=A2=9E=E4=BA=BA?= =?UTF-8?q?=E5=91=98=E5=B2=97=E4=BD=8D=E8=B0=83=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/hrm/migrations/0026_employeetransfer.py | 46 +++++++++++++++++++ .../migrations/0027_alter_leave_leave_type.py | 18 ++++++++ apps/hrm/models.py | 24 +++++++++- apps/hrm/serializers.py | 20 +++++++- apps/hrm/services.py | 20 +++++++- apps/hrm/urls.py | 3 +- apps/hrm/views.py | 22 +++++++-- 7 files changed, 145 insertions(+), 8 deletions(-) create mode 100644 apps/hrm/migrations/0026_employeetransfer.py create mode 100644 apps/hrm/migrations/0027_alter_leave_leave_type.py diff --git a/apps/hrm/migrations/0026_employeetransfer.py b/apps/hrm/migrations/0026_employeetransfer.py new file mode 100644 index 00000000..35364fff --- /dev/null +++ b/apps/hrm/migrations/0026_employeetransfer.py @@ -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, + }, + ), + ] diff --git a/apps/hrm/migrations/0027_alter_leave_leave_type.py b/apps/hrm/migrations/0027_alter_leave_leave_type.py new file mode 100644 index 00000000..a2d2cf87 --- /dev/null +++ b/apps/hrm/migrations/0027_alter_leave_leave_type.py @@ -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='请假类型'), + ), + ] diff --git a/apps/hrm/models.py b/apps/hrm/models.py index 29707d9f..842e4d7a 100755 --- a/apps/hrm/models.py +++ b/apps/hrm/models.py @@ -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) \ No newline at end of file + 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) \ No newline at end of file diff --git a/apps/hrm/serializers.py b/apps/hrm/serializers.py index 1ff98ace..bac62b84 100755 --- a/apps/hrm/serializers.py +++ b/apps/hrm/serializers.py @@ -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) \ No newline at end of file diff --git a/apps/hrm/services.py b/apps/hrm/services.py index 3d53fd72..0fe45fa7 100755 --- a/apps/hrm/services.py +++ b/apps/hrm/services.py @@ -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() diff --git a/apps/hrm/urls.py b/apps/hrm/urls.py index da6516a2..b7b037ae 100755 --- a/apps/hrm/urls.py +++ b/apps/hrm/urls.py @@ -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)), ] diff --git a/apps/hrm/views.py b/apps/hrm/views.py index 4ffbe71b..209b79af 100755 --- a/apps/hrm/views.py +++ b/apps/hrm/views.py @@ -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} \ No newline at end of file + 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} \ No newline at end of file From beef2b3e54f434303c24e19a6f0f424a246e0855 Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Wed, 28 Jan 2026 09:57:13 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=E4=BA=BA=E5=91=98=E8=B0=83=E5=B2=97?= =?UTF-8?q?=E7=94=B3=E8=AF=B7=20=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hrm/migrations/0028_auto_20260126_1445.py | 23 +++++++++++++++++++ apps/hrm/models.py | 4 ++-- apps/hrm/serializers.py | 9 +++++--- apps/hrm/services.py | 20 +++++++++------- 4 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 apps/hrm/migrations/0028_auto_20260126_1445.py diff --git a/apps/hrm/migrations/0028_auto_20260126_1445.py b/apps/hrm/migrations/0028_auto_20260126_1445.py new file mode 100644 index 00000000..f26b4910 --- /dev/null +++ b/apps/hrm/migrations/0028_auto_20260126_1445.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.12 on 2026-01-26 06:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hrm', '0027_alter_leave_leave_type'), + ] + + operations = [ + migrations.AlterField( + model_name='employeetransfer', + name='new_slary', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='调岗后薪资'), + ), + migrations.AlterField( + model_name='employeetransfer', + name='original_slary', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True, verbose_name='原岗位薪资'), + ), + ] diff --git a/apps/hrm/models.py b/apps/hrm/models.py index 842e4d7a..10f95b47 100755 --- a/apps/hrm/models.py +++ b/apps/hrm/models.py @@ -285,8 +285,8 @@ class EmployeeTransfer(CommonADModel): 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) + original_slary = models.DecimalField('原岗位薪资', max_digits=10, decimal_places=2, null=True, blank=True) + new_slary = models.DecimalField('调岗后薪资', max_digits=10, decimal_places=2, 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='关联工单', diff --git a/apps/hrm/serializers.py b/apps/hrm/serializers.py index bac62b84..56466b3e 100755 --- a/apps/hrm/serializers.py +++ b/apps/hrm/serializers.py @@ -382,6 +382,8 @@ class TransferSerializer(CustomModelSerializer): 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) + new_post_name = serializers.CharField(source="new_post.name", read_only=True) + original_post_name = serializers.CharField(source="original_post.name", read_only=True) class Meta: model = EmployeeTransfer fields = '__all__' @@ -391,7 +393,8 @@ class TransferSerializer(CustomModelSerializer): 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) \ No newline at end of file + if validated_data['new_post'] == validated_data['original_post']: + raise ParseError('新旧岗位相同,无需调动') + + return super().create(validated_data) \ No newline at end of file diff --git a/apps/hrm/services.py b/apps/hrm/services.py index 0fe45fa7..4fa88f11 100755 --- a/apps/hrm/services.py +++ b/apps/hrm/services.py @@ -19,6 +19,7 @@ from apps.third.tapis import dhapis from apps.utils.tools import rannum, ranstr import numpy as np from apps.wf.models import Ticket, Transition +from django.db import transaction myLogger = logging.getLogger('log') @@ -499,20 +500,23 @@ class HrmService: # 人员调岗申请 -def post_transfer(ticket: Ticket, transitons, new_ticket_data:dict): +def post_transfer(ticket: Ticket, new_ticket_data:dict, **kwargs): 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 获取调薪金额 + with transaction.atomic(): + del_count, _ = UserPost.objects.filter(post=obj.original_post, dept=obj.original_dept, user=obj.employee.user).delete() + if del_count == 0: + 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) + if k in ['new_post','original_post']: + setattr(obj, f'{k}_id', v) + else: + setattr(obj, k, v) obj.save() From 4690a78ac63260875a23c80bb1d312e34e95aa8b Mon Sep 17 00:00:00 2001 From: TianyangZhang Date: Thu, 29 Jan 2026 10:43:52 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20hrm=20-=20=E4=BF=AE=E6=94=B9=20?= =?UTF-8?q?=E4=BA=BA=E5=91=98=E8=B0=83=E5=B2=97=E5=90=8E=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E5=92=8C=E5=B2=97=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/hrm/services.py | 77 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 65 insertions(+), 12 deletions(-) diff --git a/apps/hrm/services.py b/apps/hrm/services.py index 4fa88f11..e03c9778 100755 --- a/apps/hrm/services.py +++ b/apps/hrm/services.py @@ -20,6 +20,7 @@ from apps.utils.tools import rannum, ranstr import numpy as np from apps.wf.models import Ticket, Transition from django.db import transaction +from django.db.models import F myLogger = logging.getLogger('log') @@ -500,23 +501,75 @@ class HrmService: # 人员调岗申请 -def post_transfer(ticket: Ticket, new_ticket_data:dict, **kwargs): +def post_transfer(ticket: Ticket, new_ticket_data: dict, **kwargs): + # 1️⃣ 获取调岗单 try: - obj = EmployeeTransfer.objects.get(id=new_ticket_data['t_id']) + obj = EmployeeTransfer.objects.select_related( + 'employee', 'employee__user' + ).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 - with transaction.atomic(): - del_count, _ = UserPost.objects.filter(post=obj.original_post, dept=obj.original_dept, user=obj.employee.user).delete() - if del_count == 0: - 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(): - if k in ['new_post','original_post']: + + employee = obj.employee + user = employee.user + + if not user: + raise ParseError('员工未绑定系统账号,无法执行调岗') + + # 2️⃣ 先更新 EmployeeTransfer(避免 atomic 中用到旧数据) + update_fields = [] + for k, v in new_ticket_data.items(): + if k in ['t_model', 't_id']: + continue + if k in ['new_post', 'original_post', 'new_dept', 'original_dept']: setattr(obj, f'{k}_id', v) else: setattr(obj, k, v) + update_fields.append(k) + obj.save() + # 3️⃣ 调岗事务(岗位、部门、UserPost 一致性) + with transaction.atomic(): + + # 3.1 校验并删除原岗位记录 + old_post_qs = UserPost.objects.filter( + user=user, + post=obj.original_post, + dept=obj.original_dept + ) + + if not old_post_qs.exists(): + raise ParseError('原岗位记录不存在,无法调岗') + + old_post_qs.delete() + + # 3.2 处理岗位排序(新岗位置顶) + UserPost.objects.filter(user=user).update(sort=F('sort') + 1) + + UserPost.objects.create( + user=user, + post=obj.new_post, + dept=obj.new_dept, + sort=1 + ) + + # 3.3 更新 Employee + employee.belong_dept = obj.new_dept + employee.post = obj.new_post + employee.save(update_fields=['belong_dept', 'post']) + + # 3.4 同步更新 User + User.objects.filter(id=user.id).update( + belong_dept=obj.new_dept, + post=obj.new_post + ) + + return obj + + +def validate_userdept(ticket: Ticket, new_ticket_data: dict, **kwargs): + obj = EmployeeTransfer.objects.get(id=new_ticket_data['t_id']) + exist_dept_post = UserPost.objects.filter(user=obj.employee.user, post=obj.original_post, dept=obj.original_dept) + if not exist_dept_post.exists(): + raise ParseError('该用户的原部门或原职务不匹配') \ No newline at end of file