diff --git a/apps/hrm/migrations/0036_empcontract_batch.py b/apps/hrm/migrations/0036_empcontract_batch.py new file mode 100644 index 00000000..909b1023 --- /dev/null +++ b/apps/hrm/migrations/0036_empcontract_batch.py @@ -0,0 +1,27 @@ +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wf', '0001_initial'), + ('hrm', '0035_rename_band_card_employee_bank_card'), + ] + + operations = [ + migrations.AlterField( + model_name='empcontract', + name='employee', + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, + to='hrm.employee', verbose_name='人员信息'), + ), + migrations.AlterField( + model_name='empcontract', + name='ticket', + field=models.ForeignKey( + blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, + related_name='contract_ticket', to='wf.ticket', verbose_name='关联工单'), + ), + ] diff --git a/apps/hrm/migrations/0037_alter_empcontract_counts.py b/apps/hrm/migrations/0037_alter_empcontract_counts.py new file mode 100644 index 00000000..fc9a5ce7 --- /dev/null +++ b/apps/hrm/migrations/0037_alter_empcontract_counts.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2026-05-13 03:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('hrm', '0036_empcontract_batch'), + ] + + operations = [ + migrations.AlterField( + model_name='empcontract', + name='counts', + field=models.PositiveSmallIntegerField(default=0, verbose_name='合同变更次数'), + ), + ] diff --git a/apps/hrm/models.py b/apps/hrm/models.py index 19b52f0c..b5fdda3b 100755 --- a/apps/hrm/models.py +++ b/apps/hrm/models.py @@ -354,8 +354,8 @@ class EmpContract(CommonAModel): """ TN:劳动合同 """ - employee = models.OneToOneField(Employee, verbose_name='人员信息', on_delete=models.SET_NULL, null=True, blank=True) - ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单', + employee = models.ForeignKey(Employee, verbose_name='人员信息', on_delete=models.SET_NULL, null=True, blank=True) + ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE, related_name='contract_ticket', null=True, blank=True) counts = models.PositiveSmallIntegerField('合同变更次数', default=0) plan_renewal = models.DateField('应续签', null=True, blank=True) diff --git a/apps/hrm/serializers.py b/apps/hrm/serializers.py index b438375a..7c72621a 100755 --- a/apps/hrm/serializers.py +++ b/apps/hrm/serializers.py @@ -425,6 +425,22 @@ class EmpContractSerializer(CustomModelSerializer): gender = serializers.CharField(source="employee.gender", read_only=True) join_date = serializers.CharField(source="employee.start_date", read_only=True) end_contract = serializers.CharField(source="employee.contract_end_date", read_only=True) + batch_employees = serializers.SerializerMethodField() + + def get_batch_employees(self, obj): + if obj.ticket_id: + siblings = EmpContract.objects.filter(ticket_id=obj.ticket_id).select_related( + 'employee', 'employee__post', 'employee__belong_dept') + if siblings.count() > 1: + return [{ + 'employee_name': s.employee.name if s.employee else '', + 'post_name': s.employee.post.name if s.employee and s.employee.post else '', + 'dept_name': s.employee.belong_dept.name if s.employee and s.employee.belong_dept else '', + 'join_date': str(s.employee.start_date or '') if s.employee else '', + 'end_contract': str(s.employee.contract_end_date or '') if s.employee else '', + } for s in siblings] + return [] + class Meta: model = EmpContract fields = '__all__' \ No newline at end of file diff --git a/apps/hrm/views.py b/apps/hrm/views.py index 8f59772e..21c8da5d 100755 --- a/apps/hrm/views.py +++ b/apps/hrm/views.py @@ -33,8 +33,9 @@ from datetime import datetime from apps.utils.export import export_excel from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet, EuModelViewSet from apps.utils.mixins import BulkCreateModelMixin, BulkDestroyModelMixin, CustomListModelMixin, RetrieveModelMixin -from apps.wf.models import Ticket +from apps.wf.models import Ticket, Workflow, State from apps.wf.mixins import TicketMixin +from apps.wf.services import WfService from apps.system.models import Post, Dept from django.db.models import DateField from datetime import datetime, date @@ -825,3 +826,49 @@ class EmpContractViewSet(TicketMixin, EuModelViewSet): def gen_other_ticket_data(self, instance): return {"name": instance.employee.name if instance.employee.name else None} + def perform_create(self, serializer): + result = serializer.save() + is_batch = isinstance(result, list) + instances = result if is_batch else [result] + handler = self.request.user + + workflow_key = self.get_workflow_key(instances[0]) + if not workflow_key: + raise ParseError('工作流异常:必须赋值workflow_key') + try: + wf = Workflow.objects.get(key=workflow_key) + except Exception as e: + raise ParseError(f'工作流{workflow_key}异常:{e}') + + # 批量时创建一个工单,所有记录共享 + if is_batch: + names = [ins.employee.name for ins in instances if ins.employee] + ticket_data = { + "t_model": "EmpContract", + "t_id": str(instances[0].id), + "batch": True, + "count": len(instances), + "name": f"批量合同变更({len(instances)}人)", + "employees": [ + {"name": ins.employee.name, "id": str(ins.id)} for ins in instances if ins.employee + ], + } + else: + ticket_data = self.gen_ticket_data(instances[0]) + + ticket = WfService.handle_ticket(ticket=None, transition=None, workflow=wf, new_ticket_data=ticket_data, + handler=handler, oinfo={}) + for ins in instances: + ins.ticket = ticket + ins.save(update_fields=['ticket']) + + if self.ticket_auto_submit_on_create: + source_state = WfService.get_workflow_start_state(wf) + transitions = WfService.get_state_transitions(source_state) + if transitions.count() == 1: + transition = transitions.first() + WfService.handle_ticket(ticket=ticket, transition=transition, new_ticket_data=ticket_data, + handler=handler, oinfo={}) + else: + raise ParseError(f'工作流{workflow_key}异常:有多个或无后续状态;不可处理') +