校验上传的证件照片

This commit is contained in:
曹前明 2022-07-07 17:30:02 +08:00
parent 3f0d73416b
commit b04d372e19
12 changed files with 140 additions and 51 deletions

View File

@ -61,10 +61,11 @@ class Access(CommonADModel):
type = models.PositiveSmallIntegerField('准入类型', choices=ACCESS_CHOICE)
area = models.ForeignKey(Area, verbose_name='关联区域',
on_delete=models.CASCADE)
obj_cate = models.CharField('对象类型', max_length=20, help_text='post/org/people')
obj_cate = models.CharField('对象类型', max_length=20, help_text='post/org/people/visit')
post = models.ForeignKey(Post, verbose_name='关联岗位', on_delete=models.CASCADE, null=True, blank=True)
dept = models.ForeignKey(Dept, verbose_name='关联部门', on_delete=models.CASCADE, null=True, blank=True)
employee = models.ForeignKey(Employee, verbose_name='关联人员', on_delete=models.CASCADE, null=True, blank=True)
visit = models.ForeignKey('vm.visit', verbose_name='关联访客项目', on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True)
stay_minute_min = models.PositiveSmallIntegerField('最短停留时间', default=0)
stay_minute_max = models.PositiveSmallIntegerField('最长停留时间', default=0)
sort = models.PositiveSmallIntegerField('排序', default=1)

View File

@ -1,8 +1,28 @@
from apps.opm.models import Operation, Opl
from apps.opm.models import Operation, Opl, OplWorker
from apps.opm.serializers import OplCloseSerializer
from apps.wf.models import Ticket, Transition
def get_op_manager(state, ticket, new_ticket_data, handler):
"""_summary_
Args:
state (_type_): 工作流节点实例
ticket (_type_): 工单实例
new_ticket_data (_type_): 提交的工单数据
handler (_type_): 处理人实例
"""
opl = Opl.objects.filter(ticket=ticket).first()
if opl:
return [opl.charger.id]
def get_op_workers(state, ticket, new_ticket_data, handler):
opl = Opl.objects.filter(ticket=ticket).first()
if opl:
return list(OplWorker.objects.filter(opl=opl).values_list('worker__id', flat=True))
def bind_opl(ticket: Ticket, transition: Transition, new_ticket_data: dict):
opl = Opl.objects.get(id=new_ticket_data['opl'])
ticket_data = ticket.ticket_data

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.12 on 2022-07-07 07:22
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wf', '0003_ticket_belong_dept'),
('vm', '0002_visit_visitors'),
]
operations = [
migrations.AddField(
model_name='visit',
name='ticket',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='wf.ticket', verbose_name='关联工单'),
),
]

View File

@ -2,6 +2,7 @@ from django.db import models
from apps.hrm.models import Employee
from apps.utils.models import CommonAModel, CommonBModel, BaseModel
from apps.system.models import User
from apps.wf.models import Ticket
# Create your models here.
@ -42,6 +43,8 @@ class Visit(CommonBModel):
count_people = models.PositiveSmallIntegerField('来访人数', null=True, blank=True)
receptionist = models.ForeignKey(User, verbose_name='接待人', on_delete=models.CASCADE)
visitors = models.ManyToManyField('vm.visitor', through='vm.vpeople', related_name='v_visitors')
ticket = models.ForeignKey(Ticket, verbose_name='关联工单',
on_delete=models.SET_NULL, null=True, blank=True)
# create_by 创建人

View File

@ -5,6 +5,9 @@ from apps.vm.models import Visit, Visitor, Vpeople
from apps.hrm.serializers import phone_check
from rest_framework import serializers
from rest_framework.exceptions import ParseError
from django.db import transaction
from apps.third.clients import dhClient
from apps.third.tapis import dhapis
class VisitCreateUpdateSerializer(CustomModelSerializer):
@ -27,6 +30,12 @@ class VisitorCreateSerializer(CustomModelSerializer):
model = Visitor
fields = ['name', 'phone', 'photo', 'id_number']
def create(self, validated_data):
with transaction.atomic():
# 校验上传的证件照
dhClient.request(**dhapis['person_img_upload'], file_path_rela=validated_data['photo'])
super().create(validated_data)
class VisitorSerializer(CustomModelSerializer):
class Meta:

38
apps/vm/services.py Normal file
View File

@ -0,0 +1,38 @@
from apps.hrm.models import Employee
from apps.vm.models import Visit, Vpeople
def bind_visit(ticket, transition, new_ticket_data: dict):
visit = Visit.objects.get(id=new_ticket_data['visit'])
visit.ticket = ticket
if visit.state == Visit.V_CREATE:
visit.state = Visit.V_AUDIT
visit.save()
def get_receptionist(state, ticket, new_ticket_data, handler):
visit = Visit.objects.filter(ticket=ticket).first()
if visit:
return [visit.receptionist.id]
def visit_audit_end(ticket):
visit = Visit.objects.get(ticket=ticket)
if visit.state == Visit.V_AUDIT:
visit.state = Visit.V_ENTER
visit.save()
# 更新企业访客人员库
for i in Vpeople.objects.filter(visit=visit):
visitor = i.visitor
ep = Employee.objects.filter(id_number=visitor.id_number, type='visitor').first()
if ep:
pass
else:
ep = Employee()
ep.name = visitor.name
ep.phone = visitor.phone
ep.photo = visitor.photo
ep.id_number = visitor.id_number
ep.save()
visitor.employee = ep
visitor.save()

View File

@ -6,25 +6,3 @@ from apps.vm.models import Visit, Vpeople
from celery import shared_task
@shared_task(base=CustomTask)
def visit_audit_end(ticket_id):
visit = Visit.objects.get(ticket__id=ticket_id)
if visit.state == Visit.V_AUDIT:
visit.state = Visit.V_ENTER
visit.save()
# 更新企业访客人员库
for i in Vpeople.objects.filter(visit=visit):
visitor = i.visitor
ep = Employee.objects.filter(id_number=visitor.id_number).first()
if ep:
pass
else:
ep = Employee()
ep.name = visitor.name
ep.phone = visitor.phone
ep.photo = visitor.photo
ep.id_number = visitor.id_number
ep.type = 'visitor'
ep.save()
visitor.employee = ep
visitor.save()

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.12 on 2022-07-07 07:11
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('system', '0002_user_post'),
('wf', '0002_auto_20220707_0957'),
]
operations = [
migrations.AddField(
model_name='ticket',
name='belong_dept',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ticket_belong_dept', to='system.dept', verbose_name='所属部门'),
),
]

View File

@ -1,5 +1,5 @@
from django.db import models
from apps.utils.models import CommonAModel
from apps.utils.models import CommonAModel, CommonBModel
from apps.system.models import User
from apps.utils.models import BaseModel
@ -223,7 +223,7 @@ class CustomField(CommonAModel):
parent = models.ForeignKey('self', verbose_name='父字段', on_delete=models.SET_NULL, null=True, blank=True)
class Ticket(CommonAModel):
class Ticket(CommonBModel):
"""
工单
"""

View File

@ -165,7 +165,7 @@ class WfService(object):
module, func = destination_participant.rsplit(".", 1)
m = importlib.import_module(module)
f = getattr(m, func)
destination_participant = f(state=state, ticket=ticket, new_ticket_data=new_ticket_data, hander=handler)
destination_participant = f(state=state, ticket=ticket, new_ticket_data=new_ticket_data, handler=handler)
# else:
# destination_participant = getattr(GetParticipants, destination_participant)(
# state=state, ticket=ticket, new_ticket_data=new_ticket_data, hander=handler)
@ -181,10 +181,10 @@ class WfService(object):
depts = get_parent_queryset(ticket.belong_dept)
user_queryset = user_queryset.filter(dept__in=depts)
elif state.filter_policy == 2:
depts = get_parent_queryset(ticket.create_by.dept)
depts = get_parent_queryset(ticket.create_by.belong_dept)
user_queryset = user_queryset.filter(dept__in=depts)
elif state.filter_policy == 3:
depts = get_parent_queryset(handler.dept)
depts = get_parent_queryset(handler.belong_dept)
user_queryset = user_queryset.filter(dept__in=depts)
destination_participant = list(user_queryset.values_list('id', flat=True))
if type(destination_participant) == list:
@ -214,7 +214,7 @@ class WfService(object):
current_participant_count = 0
participant_type = ticket.participant_type
participant = ticket.participant
state = ticket.stateF
state = ticket.state
if participant_type == State.PARTICIPANT_TYPE_PERSONAL:
if user.id != participant:
return dict(permission=False, msg="非当前处理人", need_accept=False)
@ -365,6 +365,8 @@ class WfService(object):
participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC,
participant=None, participant_cc=destination_state.participant_cc)
cls.task_ticket(ticket=ticket)
return ticket
@classmethod
@ -372,22 +374,13 @@ class WfService(object):
"""
执行任务(自定义任务或通知)
"""
# 如果目标状态是脚本则异步执行
state = ticket.state
if state.participant_type == State.PARTICIPANT_TYPE_ROBOT:
module, func = state.participant.rsplit(".", 1)
m = importlib.import_module(module)
f = getattr(m, func)
ticket.script_run_last_result = False
ticket.save()
f.delay(ticket_id=ticket.id, script_str=state.participant) # 里面要加入回调才能继续流转
# 如果目标状态有func,由func执行额外操作(比如发送通知)
if state.on_reach_func:
module, func = state.func.rsplit(".", 1)
module, func = state.on_reach_func.rsplit(".", 1)
m = importlib.import_module(module)
f = getattr(m, func)
f.delay(ticket_id=ticket.id) # 不用加入回调
f(ticket=ticket) # 同步执行
else:
# wf默认发送通知
last_log = TicketFlow.objects.filter(ticket=ticket).order_by('-create_time').first()
@ -395,5 +388,14 @@ class WfService(object):
last_log.intervene_type == Transition.TRANSITION_INTERVENE_TYPE_DELIVER or
ticket.in_add_node):
# 如果状态变化或是转交加签的情况再发送通知
from tasks import send_ticket_notice
from apps.wf.tasks import send_ticket_notice
send_ticket_notice.delay(ticket_id=ticket.id)
# 如果目标状态是脚本则异步执行
if state.participant_type == State.PARTICIPANT_TYPE_ROBOT:
module, func = state.participant.rsplit(".", 1)
m = importlib.import_module(module)
f = getattr(m, func)
ticket.script_run_last_result = False
ticket.save()
f.delay(ticket_id=ticket.id, script_str=state.participant) # 里面要加入回调才能继续流转

View File

@ -7,9 +7,9 @@ from apps.wf.serializers import TicketDetailSerializer
@shared_task(base=CustomTask)
def send_ticket_notice(ticket):
def send_ticket_notice(ticket_id):
"""
发送通知
"""
data = TicketDetailSerializer(instance=ticket).data
pass

View File

@ -42,6 +42,9 @@ class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet):
ordering_fields = ['create_time']
ordering = ['-create_time']
def get_object(self):
return super().get_object()
@action(methods=['get'], detail=True, perms_map={'get': 'workflow:update'},
pagination_class=None, serializer_class=StateSerializer)
def states(self, request, pk=None):
@ -93,7 +96,6 @@ class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet):
ret['field_list'] = field_list
return Response(ret)
class StateViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'get': '*', 'post': 'workflow:update',
'put': 'workflow:update', 'delete': 'workflow:update'}
@ -130,7 +132,7 @@ class CustomFieldViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin,
class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, RetrieveModelMixin, GenericViewSet):
perms_map = {'get': '*', 'post': 'ticket:create'}
perms_map = {'get': '*', 'post': '*'}
queryset = Ticket.objects.all()
serializer_class = TicketSerializer
search_fields = ['title']
@ -184,7 +186,7 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
create_by=request.user,
create_time=timezone.now(),
act_state=Ticket.TICKET_ACT_STATE_DRAFT,
belong_dept=request.user.dept,
belong_dept=request.user.belong_dept,
ticket_data=save_ticket_data) # 先创建出来
# 更新title和sn
title = vdata.get('title', '')
@ -198,7 +200,6 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
ticket.save()
ticket = WfService.handle_ticket(ticket=ticket, transition=transition, new_ticket_data=ticket_data,
handler=request.user, created=True)
WfService.task_ticket(ticket)
return Response(TicketSerializer(instance=ticket).data)
@action(methods=['get'], detail=False, perms_map={'get': '*'})
@ -228,7 +229,6 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
ticket = WfService.handle_ticket(ticket=ticket, transition=vdata['transition'],
new_ticket_data=new_ticket_data, handler=request.user,
suggestion=vdata['suggestion'])
WfService.task_ticket(ticket)
return Response(TicketSerializer(instance=ticket).data)
@action(methods=['post'], detail=True, perms_map={'post': '*'})
@ -252,7 +252,6 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
suggestion=vdata['suggestion'], participant_type=State.PARTICIPANT_TYPE_PERSONAL,
intervene_type=Transition.TRANSITION_INTERVENE_TYPE_DELIVER,
participant=request.user, transition=None)
WfService.task_ticket(ticket)
return Response()
@action(methods=['get'], detail=True, perms_map={'get': '*'})
@ -350,7 +349,6 @@ class TicketViewSet(CreateUpdateCustomMixin, CreateModelMixin, ListModelMixin, R
suggestion=suggestion, participant_type=State.PARTICIPANT_TYPE_PERSONAL,
intervene_type=Transition.TRANSITION_INTERVENE_TYPE_ADD_NODE,
participant=request.user, transition=None)
WfService.task_ticket(ticket)
return Response()
@action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=TicketAddNodeEndSerializer)