feat: 新增hrm --人员交接表
This commit is contained in:
parent
dec8650af1
commit
b250b9b078
|
|
@ -0,0 +1,57 @@
|
|||
# Generated by Django 3.2.12 on 2025-12-22 05:40
|
||||
|
||||
from django.conf import settings
|
||||
import django.core.validators
|
||||
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),
|
||||
('system', '0006_auto_20241213_1249'),
|
||||
('wf', '0006_auto_20251215_1645'),
|
||||
('hrm', '0022_empneed'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='EmpPersonInfo',
|
||||
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='删除标记')),
|
||||
('name', models.CharField(max_length=20, verbose_name='姓名')),
|
||||
('gender', models.CharField(default='男', max_length=10, verbose_name='性别')),
|
||||
('IDcard', models.CharField(max_length=20, verbose_name='身份证号')),
|
||||
('phone', models.CharField(blank=True, max_length=20, null=True, validators=[django.core.validators.RegexValidator('^1[3456789]\\d{9}$', '手机号码格式不正确')], verbose_name='手机号')),
|
||||
('note', 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='emppersoninfo_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='emppersoninfo_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='EmpJoin',
|
||||
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='删除标记')),
|
||||
('person', models.JSONField(default=list, verbose_name='人员信息')),
|
||||
('join_date', models.DateField(verbose_name='入职日期')),
|
||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='empjoin_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||
('dept_need', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.dept', verbose_name='入职部门')),
|
||||
('ticket', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='empjoin_ticket', to='wf.ticket', verbose_name='关联工单')),
|
||||
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='empjoin_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -4,8 +4,9 @@ from apps.system.models import Post, User
|
|||
from apps.utils.models import BaseModel, CommonADModel, CommonAModel, CommonBModel
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
from django.core.validators import RegexValidator
|
||||
|
||||
|
||||
PHONE_VALIDATOR = RegexValidator(r'^1[3456789]\d{9}$', '手机号码格式不正确')
|
||||
class Employee(CommonBModel):
|
||||
"""
|
||||
TN:员工信息
|
||||
|
|
@ -220,4 +221,27 @@ class EmpNeed(CommonADModel):
|
|||
education = models.CharField('学历要求', max_length=50, help_text='高中/大专/不限')
|
||||
professional_requirement = models.TextField(verbose_name="相关专业及技能要求", null=True, blank=True)
|
||||
ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单',
|
||||
on_delete=models.CASCADE, related_name='empneed_ticket', null=True, blank=True)
|
||||
on_delete=models.CASCADE, related_name='empneed_ticket', null=True, blank=True)
|
||||
|
||||
|
||||
class EmpJoin(CommonADModel):
|
||||
"""
|
||||
TN:员工入职
|
||||
"""
|
||||
dept_need = models.ForeignKey('system.Dept', verbose_name='入职部门', on_delete=models.CASCADE)
|
||||
ticket = models.OneToOneField('wf.ticket', verbose_name='关联工单',
|
||||
on_delete=models.CASCADE, related_name='empjoin_ticket', null=True, blank=True)
|
||||
person = models.JSONField('人员信息', default=list)
|
||||
join_date = models.DateField('入职日期')
|
||||
|
||||
|
||||
class EmpPersonInfo(CommonADModel):
|
||||
"""
|
||||
TN:入职人员信息
|
||||
"""
|
||||
name = models.CharField('姓名', max_length=20)
|
||||
gender = models.CharField('性别', max_length=10, default='男')
|
||||
IDcard = models.CharField('身份证号', max_length=20)
|
||||
phone = models.CharField('手机号', max_length=20,validators=[PHONE_VALIDATOR], null=True, blank=True)
|
||||
note = models.TextField('备注', null=True, blank=True)
|
||||
|
||||
|
|
@ -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)
|
||||
NotWorkRemark, Attendance, Resignation, EmpNeed, EmpJoin, EmpPersonInfo)
|
||||
from apps.system.serializers import DeptSimpleSerializer, UserSimpleSerializer
|
||||
from django.db import transaction
|
||||
from django.core.cache import cache
|
||||
|
|
@ -347,4 +347,59 @@ class EmpNeedSerializer(CustomModelSerializer):
|
|||
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
||||
class Meta:
|
||||
model = EmpNeed
|
||||
fields = '__all__'
|
||||
fields = '__all__'
|
||||
|
||||
class EmpJoinSerializer(CustomModelSerializer):
|
||||
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
|
||||
class Meta:
|
||||
model = EmpJoin
|
||||
fields = '__all__'
|
||||
|
||||
class EmpPersonInfoSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = EmpPersonInfo
|
||||
fields = (
|
||||
'name',
|
||||
'gender',
|
||||
'IDcard',
|
||||
'phone',
|
||||
'note',
|
||||
)
|
||||
|
||||
class EmpJoinApproveSerializer(CustomModelSerializer):
|
||||
empjoin_id = serializers.IntegerField()
|
||||
|
||||
def validate_empjoin_id(self, value):
|
||||
try:
|
||||
empjoin = EmpJoin.objects.get(id=value)
|
||||
except EmpJoin.DoesNotExist:
|
||||
raise ParseError('该入职申请不存在')
|
||||
if not isinstance(empjoin.person, list) or not empjoin.person:
|
||||
raise ParseError('该入职申请未添加人员')
|
||||
self.empjoin = empjoin
|
||||
return value
|
||||
|
||||
def validate(self, attrs):
|
||||
"""
|
||||
校验 person 中每一个人员
|
||||
"""
|
||||
self.person_serializers = []
|
||||
errors = []
|
||||
for index, item in enumerate(self.empjoin.person):
|
||||
serializer = EmpPersonInfoSerializer(data=item)
|
||||
if serializer.is_valid():
|
||||
self.person_serializers.append(serializer)
|
||||
else:
|
||||
errors.append({
|
||||
"index": index,
|
||||
"errors": serializer.errors
|
||||
})
|
||||
if errors:
|
||||
raise serializers.ValidationError({"person": errors})
|
||||
return attrs
|
||||
|
||||
@transaction.atomic
|
||||
def create(self, validated_data):
|
||||
objs = [EmpPersonInfo(**serializer.validated_data) for serializer in self.person_serializers]
|
||||
EmpPersonInfo.objects.bulk_create(objs)
|
||||
return objs
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
from apps.hrm.views import (CertificateViewSet, ClockRecordViewSet, EmployeeViewSet, NotWorkRemarkViewSet, EmpNeedViewSet,
|
||||
AttendanceViewSet, ResignationViewSet)
|
||||
AttendanceViewSet, ResignationViewSet, EmpJoinViewSet)
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
|
|
@ -15,6 +15,7 @@ router.register('certificate', CertificateViewSet, basename='certificate')
|
|||
router.register('attendance', AttendanceViewSet, basename='attendance')
|
||||
router.register('resignation', ResignationViewSet, basename='resignation')
|
||||
router.register('empneed', EmpNeedViewSet, basename='empneed')
|
||||
router.register('empjoin', EmpJoinViewSet, basename='empjoin')
|
||||
urlpatterns = [
|
||||
path(API_BASE_URL, include(router.urls)),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -12,15 +12,15 @@ 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
|
||||
from apps.hrm.serializers import (CertificateCreateUpdateSerializer, CertificateSerializer, ChannelAuthoritySerializer,
|
||||
from apps.hrm.models import Certificate, ClockRecord, Employee, NotWorkRemark, Attendance, Resignation, EmpNeed, EmpJoin
|
||||
from apps.hrm.serializers import (CertificateCreateUpdateSerializer, CertificateSerializer, ChannelAuthoritySerializer, EmpJoinSerializer,
|
||||
ClockRecordListSerializer,
|
||||
EmployeeCreateUpdateSerializer, EmployeeDetailSerializer, EmployeeImproveSerializer,
|
||||
EmployeeNotWorkRemarkSerializer,
|
||||
EmployeeSerializer,
|
||||
ClockRecordSimpleSerializer, ClockRecordCreateSerializer,
|
||||
NotWorkRemarkListSerializer, CorrectSerializer, AttendanceSerializer,
|
||||
ResignationSerializer, EmpNeedSerializer)
|
||||
ResignationSerializer, EmpNeedSerializer, EmpJoinApproveSerializer)
|
||||
from apps.hrm.services import HrmService
|
||||
|
||||
from apps.third.dahua import dhClient
|
||||
|
|
@ -430,4 +430,20 @@ class EmpNeedViewSet(TicketMixin, EuModelViewSet):
|
|||
workflow_key = "wf_empneed"
|
||||
|
||||
def gen_other_ticket_data(self, instance):
|
||||
return {"post_need": instance.post_need}
|
||||
return {"post_need": instance.post_need}
|
||||
|
||||
|
||||
class EmpJoinViewSet(TicketMixin, EuModelViewSet):
|
||||
queryset = EmpJoin.objects.all()
|
||||
serializer_class = EmpJoinSerializer
|
||||
workflow_key = "wf_empjoin"
|
||||
|
||||
@action(methods=['post'], detail=True)
|
||||
def approve(self, request, pk=None):
|
||||
serializer = EmpJoinApproveSerializer(data={'empjoin_id': pk})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
person = serializer.save()
|
||||
return Response({
|
||||
"msg":"审批通过,人员入库",
|
||||
"count": len(person)
|
||||
})
|
||||
Loading…
Reference in New Issue