feat: rpj member 后入厂和提前离厂
This commit is contained in:
parent
1f8963514f
commit
a4c54c48e0
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.2.12 on 2023-03-23 09:40
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('third', '0007_tdevice_mtask_uid'),
|
||||
('ecm', '0008_alter_algochannel_always_on'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='algochannel',
|
||||
name='algo',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ac_algo', to='ecm.eventcate', verbose_name='关联算法'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='algochannel',
|
||||
name='vchannel',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ac_vchannel', to='third.tdevice', verbose_name='视频通道'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,36 @@
|
|||
# Generated by Django 3.2.12 on 2023-03-23 09:40
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('rpm', '0007_alter_rcertificate_number'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='rpjmember',
|
||||
name='note',
|
||||
field=models.CharField(blank=True, help_text='后入厂/提前离厂', max_length=20, null=True, verbose_name='备注'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='RpjLog',
|
||||
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='删除标记')),
|
||||
('operation', models.CharField(help_text='member_come/member_leave', max_length=20, verbose_name='操作类型')),
|
||||
('reason', models.CharField(blank=True, max_length=100, null=True, verbose_name='原因')),
|
||||
('remployee', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rpm.remployee', verbose_name='关联人员')),
|
||||
('rpj', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rpm.rpj', verbose_name='关联项目')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -124,6 +124,7 @@ class Rpjmember(BaseModel):
|
|||
duty = models.CharField('职责', max_length=20, null=True, blank=True)
|
||||
is_manager = models.BooleanField('是否项目负责人', default=False)
|
||||
rcertificates = models.ManyToManyField(Rcertificate, through='rpm.rpjcertificate', blank=True)
|
||||
note = models.CharField('备注', max_length=20, null=True, blank=True, help_text='后入厂/提前离厂')
|
||||
|
||||
|
||||
class Rpjcertificate(BaseModel):
|
||||
|
@ -140,3 +141,15 @@ class Rpjcertificate(BaseModel):
|
|||
expiration_date = models.DateField('有效期')
|
||||
review_date = models.DateField('下一次复审日期')
|
||||
file = models.CharField('文件地址', max_length=1000, null=True, blank=True)
|
||||
|
||||
|
||||
class RpjLog(BaseModel):
|
||||
"""项目变更日志
|
||||
|
||||
Args:
|
||||
BaseModel (_type_): _description_
|
||||
"""
|
||||
rpj = models.ForeignKey(Rpj, verbose_name='关联项目', on_delete=models.CASCADE)
|
||||
operation = models.CharField('操作类型', max_length=20, help_text='member_come/member_leave')
|
||||
remployee = models.ForeignKey(Remployee, verbose_name='关联人员', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
reason = models.CharField('原因', max_length=100, null=True, blank=True)
|
||||
|
|
|
@ -14,6 +14,8 @@ from apps.third.dahua import dhClient
|
|||
from apps.third.tapis import dhapis
|
||||
from apps.utils.tools import check_id_number_e, check_phone_e
|
||||
from apps.wf.serializers import TicketSimpleSerializer
|
||||
from apps.rpm.services import rpj_member_come, rpj_certificate_in
|
||||
from apps.rpm.models import RpjLog
|
||||
|
||||
|
||||
class RpartyCreateUpdateSerializer(CustomModelSerializer):
|
||||
|
@ -158,6 +160,11 @@ class RemployeeUpdateSerializer(CustomModelSerializer):
|
|||
dhClient.request(**dhapis['person_img_upload'], file_path_rela=validated_data['photo'])
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
class RemployeeSimpleSerializer(CustomModelSerializer):
|
||||
class Meta:
|
||||
model = Remployee
|
||||
fields = ['id', 'name', 'photo', 'id_number']
|
||||
|
||||
|
||||
class RemployeeSerializer(CustomModelSerializer):
|
||||
rparty_name = serializers.CharField(source='rparty.name', read_only=True)
|
||||
|
@ -204,10 +211,10 @@ class RpjmemberCreatesSerializer(CustomModelSerializer):
|
|||
|
||||
class RpjmemberCreateSerializer(CustomModelSerializer):
|
||||
rcertificates = serializers.PrimaryKeyRelatedField(label='证书ID', many=True, queryset=Rcertificate.objects.all())
|
||||
|
||||
reason = serializers.CharField(label='后入厂原因', required=False, allow_blank=True)
|
||||
class Meta:
|
||||
model = Rpjmember
|
||||
fields = ['remployee', 'rpj', 'duty', 'is_manager', 'rcertificates']
|
||||
fields = ['remployee', 'rpj', 'duty', 'is_manager', 'rcertificates', 'reason']
|
||||
|
||||
def create(self, validated_data):
|
||||
rpj = validated_data['rpj']
|
||||
|
@ -239,7 +246,12 @@ class RpjmemberCreateSerializer(CustomModelSerializer):
|
|||
if ins.is_manager:
|
||||
Rpjmember.objects.exclude(id=ins.id).update(is_manager=False)
|
||||
if rpj.state in [Rpj.RPJ_ENTER, Rpj.RPJ_WORKING]: # 如果是待入厂后添加的
|
||||
pass
|
||||
# 需要执行入厂操作
|
||||
ins.note = '后入厂'
|
||||
ins.save()
|
||||
rpj_member_come(ins)
|
||||
rpj_certificate_in(ins)
|
||||
RpjLog.objects.create(rpj=rpj, operation='member_come', remployee=remployee, create_by=self.context['request'].user, reason=validated_data.get('reason', ''))
|
||||
return ins
|
||||
|
||||
|
||||
|
@ -272,9 +284,15 @@ class RpjmemberUpdateSerializer(CustomModelSerializer):
|
|||
if ins.is_manager:
|
||||
Rpjmember.objects.exclude(id=ins.id).update(is_manager=False)
|
||||
if rpj.state in [Rpj.RPJ_ENTER, Rpj.RPJ_WORKING]: # 如果是待入厂后更改的
|
||||
pass
|
||||
rpj_certificate_in(ins)
|
||||
return ins
|
||||
|
||||
class RpjLogSerializer(CustomModelSerializer):
|
||||
remployee_ = RemployeeSimpleSerializer(source='remployee', read_only=True)
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
class Meta:
|
||||
model = RpjLog
|
||||
fields = '__all__'
|
||||
|
||||
class RpjcertificateSerializer(CustomModelSerializer):
|
||||
file_f = MyFilePathField(source='file', read_only=True)
|
||||
|
|
|
@ -8,6 +8,10 @@ from apps.wf.models import Ticket, Transition
|
|||
from apps.rpm.models import Remployee, Rfile, Rparty, Rpj, Rpjcertificate, Rpjfile, Rpjmember
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from rest_framework.exceptions import ParseError
|
||||
from dateutil import tz
|
||||
from django.utils import timezone
|
||||
from datetime import datetime, timedelta
|
||||
from django.db.models import Max, Min
|
||||
|
||||
|
||||
def sync_to_rep(ep: Employee):
|
||||
|
@ -41,68 +45,142 @@ def bind_rpj(ticket: Ticket, transition: Transition, new_ticket_data: dict):
|
|||
ticket.create_by = rpj.create_by
|
||||
ticket.save()
|
||||
|
||||
def rpj_member_leave(i: Rpjmember):
|
||||
"""人员离开项目
|
||||
"""
|
||||
rpj = i.rpj
|
||||
rep = i.remployee
|
||||
ep = rep.employee
|
||||
|
||||
# 查找本人除此之外还在的项目
|
||||
rpj_qs = Rpj.objects.filter(remployees=rep, state__in = [Rpj.RPJ_WORKING, Rpj.RPJ_ENTER]).exclude(id=rpj.id)
|
||||
if rpj_qs.exists():
|
||||
leave_time__max = rpj_qs.aggregate(Max('leave_time'))['leave_time__max']
|
||||
come_time_min = rpj_qs.aggregate(Min('come_time'))['come_time__min']
|
||||
rpj_ = rpj_qs.order_by('-create_time').first()
|
||||
rpj_dept = rpj_.rparty.dept
|
||||
if ep:
|
||||
ep.belong_dept = rpj_dept
|
||||
ep.save()
|
||||
if ep.user:
|
||||
ep.user.belong_dept = rpj_dept
|
||||
ep.user.save()
|
||||
# 同步至大华人员库并下发人脸
|
||||
HrmService.sync_dahua_employee(ep, ep.photo, come_time_min, leave_time__max)
|
||||
else:
|
||||
if ep:
|
||||
ep.job_state = Employee.JOB_OFF
|
||||
ep.save()
|
||||
HrmService.sync_dahua_employee(ep, ep.photo, rpj.come_time, timezone.now() + timedelta(hours=8))
|
||||
if ep.user:
|
||||
ep.user.is_active = False
|
||||
ep.user.save()
|
||||
|
||||
def rpj_member_come(i: Rpjmember):
|
||||
"""人员入厂
|
||||
"""
|
||||
# tzinfo = tz.gettz('Asia/Shanghai')
|
||||
rep = i.remployee
|
||||
rpj = i.rpj
|
||||
rpj_dept = rpj.rparty.dept
|
||||
post = Post.objects.get(code='remployee')
|
||||
# 尝试找到人员
|
||||
ep = Employee.objects.get_queryset(all=True).filter(id_number=rep.id_number).first()
|
||||
ep2 = Employee.objects.get_queryset(all=True).filter(phone=rep.phone).first()
|
||||
if ep:
|
||||
pass
|
||||
elif ep2:
|
||||
ep = ep2
|
||||
else:
|
||||
ep = Employee()
|
||||
ep.id_number = rep.id_number
|
||||
|
||||
ep.name = rep.name
|
||||
ep.id_number = rep.id_number
|
||||
ep.gender = get_info_from_id(rep.id_number).get('gender', '男')
|
||||
ep.phone = rep.phone
|
||||
old_photo = ep.photo
|
||||
ep.photo = rep.photo
|
||||
ep.job_state = Employee.JOB_ON
|
||||
ep.type = 'remployee'
|
||||
ep.belong_dept = rpj.rparty.dept
|
||||
ep.is_deleted = False
|
||||
ep.job_state = 10
|
||||
ep.save()
|
||||
# 给相关方人员创建账户
|
||||
user_e = ep.user
|
||||
if user_e: # 如果该人员有账户
|
||||
pass
|
||||
else:
|
||||
user_e = User.objects.get_queryset(all=True).filter(phone=rep.phone).first() # 看看有没有存在的账户
|
||||
if user_e:
|
||||
user_e.is_active = True
|
||||
user_e.is_deleted = False
|
||||
else:
|
||||
user_e = User()
|
||||
user_e.username = 'RE_' + ranstr(6)
|
||||
user_e.password = make_password('0000')
|
||||
user_e.name = rep.name
|
||||
user_e.phone = rep.phone
|
||||
user_e.type = 'remployee'
|
||||
user_e.belong_dept = rpj_dept
|
||||
user_e.post = post
|
||||
user_e.save()
|
||||
# 账号划给部门
|
||||
UserPost.objects.get_or_create(user=user_e, dept=rpj_dept,
|
||||
defaults={
|
||||
'user': user_e,
|
||||
'dept': rpj_dept,
|
||||
'post': post
|
||||
})
|
||||
ep.user = user_e
|
||||
ep.save()
|
||||
# 回写
|
||||
rep.employee = ep
|
||||
rep.rpj = rpj # 更新当前入厂项目
|
||||
rep.save()
|
||||
|
||||
# come_time = rpj.come_time
|
||||
# leave_time = rpj.leave_time
|
||||
# dh_face_card_start = ep.third_info.get('dh_face_card_start', None)
|
||||
# dh_face_card_end = ep.third_info.get('dh_face_card_end', None)
|
||||
# if dh_face_card_start:
|
||||
# dh_face_card_start = datetime.strptime(dh_face_card_start, "%Y-%m-%d %H:%M:%S").replace(tzinfo=tzinfo)
|
||||
# if dh_face_card_start < come_time:
|
||||
# come_time = dh_face_card_start
|
||||
# if dh_face_card_end:
|
||||
# dh_face_card_end = datetime.strptime(dh_face_card_end, "%Y-%m-%d %H:%M:%S").replace(tzinfo=tzinfo)
|
||||
# if dh_face_card_end > leave_time:
|
||||
# leave_time = dh_face_card_end
|
||||
rpj_qs = Rpj.objects.filter(remployees=rep, state__in = [Rpj.RPJ_WORKING, Rpj.RPJ_ENTER])|Rpj.objects.filter(id=rpj.id)
|
||||
leave_time__max = rpj_qs.aggregate(Max('leave_time'))['leave_time__max']
|
||||
come_time_min = rpj_qs.aggregate(Min('come_time'))['come_time__min']
|
||||
# 同步至大华人员库并下发人脸
|
||||
HrmService.sync_dahua_employee(ep, old_photo, come_time_min, leave_time__max)
|
||||
|
||||
|
||||
def rpj_certificate_in(i: Rpjmember):
|
||||
for i in Rpjcertificate.objects.filter(rpj_member=i):
|
||||
ct = Certificate.objects.filter(number=i.number, name=i.name).first()
|
||||
if ct:
|
||||
pass
|
||||
else:
|
||||
ct = Certificate()
|
||||
ct.employee = i.rpj_member.remployee.employee
|
||||
ct.name = i.name
|
||||
ct.number = i.number
|
||||
ct.type = i.type
|
||||
ct.issue_date = i.issue_date
|
||||
ct.expiration_date = i.expiration_date
|
||||
ct.review_date = i.review_date
|
||||
ct.file = i.file
|
||||
ct.save()
|
||||
|
||||
def rpj_audit_end(ticket):
|
||||
rpj = Rpj.objects.get(ticket=ticket)
|
||||
rpj_dept = rpj.rparty.dept
|
||||
post = Post.objects.get(code='remployee')
|
||||
# 更新入厂项目人员库
|
||||
for i in Rpjmember.objects.filter(rpj=rpj):
|
||||
rep = i.remployee
|
||||
# 尝试找到人员
|
||||
ep = Employee.objects.get_queryset(all=True).filter(id_number=rep.id_number).first()
|
||||
ep2 = Employee.objects.get_queryset(all=True).filter(phone=rep.phone).first()
|
||||
if ep:
|
||||
pass
|
||||
elif ep2:
|
||||
ep = ep2
|
||||
else:
|
||||
ep = Employee()
|
||||
ep.id_number = rep.id_number
|
||||
ep.name = rep.name
|
||||
ep.id_number = rep.id_number
|
||||
ep.gender = get_info_from_id(rep.id_number).get('gender', '男')
|
||||
ep.phone = rep.phone
|
||||
ep.photo = rep.photo
|
||||
ep.type = 'remployee'
|
||||
ep.belong_dept = rpj.rparty.dept
|
||||
ep.is_deleted = False
|
||||
ep.job_state = 10
|
||||
ep.save()
|
||||
# 给相关方人员创建账户
|
||||
user_e = ep.user
|
||||
if user_e: # 如果该人员有账户
|
||||
pass
|
||||
else:
|
||||
user_e = User.objects.get_queryset(all=True).filter(phone=rep.phone).first() # 看看有没有存在的账户
|
||||
if user_e:
|
||||
user_e.is_active = True
|
||||
user_e.is_deleted = False
|
||||
else:
|
||||
user_e = User()
|
||||
user_e.username = 'RE_' + ranstr(6)
|
||||
user_e.password = make_password('0000')
|
||||
user_e.name = rep.name
|
||||
user_e.phone = rep.phone
|
||||
user_e.type = 'remployee'
|
||||
user_e.belong_dept = rpj_dept
|
||||
user_e.post = post
|
||||
user_e.save()
|
||||
# 账号划给部门
|
||||
UserPost.objects.get_or_create(user=user_e, dept=rpj_dept,
|
||||
defaults={
|
||||
'user': user_e,
|
||||
'dept': rpj_dept,
|
||||
'post': post
|
||||
})
|
||||
ep.user = user_e
|
||||
ep.save()
|
||||
# 回写
|
||||
rep.employee = ep
|
||||
rep.rpj = rpj # 更新当前入厂项目
|
||||
rep.save()
|
||||
# 同步至大华人员库并下发人脸
|
||||
HrmService.sync_dahua_employee(ep, '', rpj.come_time, rpj.leave_time)
|
||||
rpj_member_come(i)
|
||||
# 更新入厂项目人员证书库
|
||||
for i in Rpjcertificate.objects.filter(rpj_member__rpj=rpj):
|
||||
ct = Certificate.objects.filter(number=i.number, name=i.name).first()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from apps.rpm.views import RcertificateViewSet, RpartyViewSet, RemployeeViewSet, RfileViewSet, RpjViewSet, RpjfileViewSet, RpjmemberViewSet
|
||||
from apps.rpm.views import (RcertificateViewSet, RpartyViewSet, RemployeeViewSet, RfileViewSet, RpjViewSet,
|
||||
RpjfileViewSet, RpjmemberViewSet, RpjLogViewSet)
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
|
@ -12,6 +13,7 @@ router.register('rcertificate', RcertificateViewSet, basename='rcertificate')
|
|||
router.register('rfile', RfileViewSet, basename='rfile')
|
||||
router.register('rpj', RpjViewSet, basename='rpj')
|
||||
router.register('rpj_member', RpjmemberViewSet, basename='rpj_member')
|
||||
router.register('rpj_log', RpjLogViewSet, basename='rpj_log')
|
||||
router.register('rpj_file', RpjfileViewSet, basename='rpj_file')
|
||||
urlpatterns = [
|
||||
path(API_BASE_URL, include(router.urls)),
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from apps.rpm.filters import RpjFilterSet
|
||||
from apps.rpm.models import Rcertificate, Remployee, Rparty, Rfile, Rpjfile, Rpjmember, Rpj
|
||||
from apps.rpm.models import Rcertificate, Remployee, Rparty, Rfile, Rpjfile, Rpjmember, Rpj, RpjLog
|
||||
from apps.rpm.serializers import (RcertificateCreateUpdateSerializer,
|
||||
RcertificateSerializer, RemployeeCreateSerializer, RemployeeSerializer,
|
||||
RemployeeUpdateSerializer, RpartyAssignSerializer, RpartyCreateUpdateSerializer,
|
||||
RfileListSerializer, RpartySerializer, RpjListSerializer, RpjfileSerializer,
|
||||
RpjfileUpdateSerializer, RpjmemberCreateSerializer,
|
||||
RpjfileUpdateSerializer, RpjmemberCreateSerializer, RpjLogSerializer,
|
||||
RpjCreateSerializer, RpjUpdateSerializer, RpjmemberSerializer, RpjmemberUpdateSerializer)
|
||||
from apps.rpm.services import sync_to_rep
|
||||
from apps.rpm.services import sync_to_rep, rpj_member_leave
|
||||
from apps.system.models import Dictionary, Post, User, UserPost
|
||||
from apps.system.serializers import UserCreateSerializer
|
||||
from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
|
||||
|
@ -224,10 +224,31 @@ class RpjmemberViewSet(CustomModelViewSet):
|
|||
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
obj = self.get_object()
|
||||
if obj.rpj.state != Rpj.RPJ_CREATE:
|
||||
raise ParseError('项目非创建状态不可删除')
|
||||
if obj.rpj.state in [Rpj.RPJ_DONE, Rpj.RPJ_CLOSE]:
|
||||
raise ParseError('成员在该状态不可删除')
|
||||
else:
|
||||
pass
|
||||
return super().destroy(request, *args, **kwargs)
|
||||
|
||||
@action(methods=['post'], detail=True, perms_map={'post': 'rpj.update'})
|
||||
@transaction.atomic
|
||||
def leave(self, request, pk=None):
|
||||
"""提前离厂
|
||||
|
||||
提前离厂
|
||||
"""
|
||||
obj = self.get_object()
|
||||
rpj_member_leave(obj)
|
||||
RpjLog.objects.create(rpj=obj.rpj, operation='member_leave', remployee=obj.remployee, create_by=request.user, reason=request.data.get('reason', ''))
|
||||
return Response()
|
||||
|
||||
class RpjLogViewSet(ListModelMixin, CustomGenericViewSet):
|
||||
perms_map = {'get': '*'}
|
||||
queryset = RpjLog.objects.all()
|
||||
serializer_class = RpjLogSerializer
|
||||
select_related_fields = ['rpj', 'remployee', 'create_by']
|
||||
filterset_fields = ['rpj', 'remployee']
|
||||
ordering = ['-create_time']
|
||||
|
||||
class RpjfileViewSet(UpdateModelMixin, DestroyModelMixin, ListModelMixin, CustomGenericViewSet):
|
||||
perms_map = {'get': '*', 'put': 'rpj.update', 'delete': 'rpj.update'}
|
||||
|
|
|
@ -29,7 +29,7 @@ DEBUG = conf.DEBUG
|
|||
ALLOWED_HOSTS = ['*']
|
||||
|
||||
SYS_NAME = 'XT_EHS'
|
||||
SYS_VERSION = '2.00.12'
|
||||
SYS_VERSION = '2.00.13'
|
||||
PROJECT_NAME = conf.PROJECT_NAME
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue