386 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			386 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Python
		
	
	
	
| from django.shortcuts import render
 | |
| from django.conf import settings
 | |
| from rest_framework.decorators import action
 | |
| from rest_framework.mixins import ListModelMixin
 | |
| from rest_framework.response import Response
 | |
| from rest_framework.exceptions import ParseError
 | |
| 
 | |
| from apps.mtm.filters import GoalFilter, MaterialFilter, RouteFilter
 | |
| from apps.mtm.models import Goal, Material, Mgroup, Shift, Team, Process, Route, TeamMember, RoutePack, Srule, RouteMat
 | |
| from apps.mtm.serializers import (GoalSerializer, MaterialSerializer,
 | |
|                                   MgroupGoalYearSerializer, MgroupSerializer, MgroupDaysSerializer,
 | |
|                                   ShiftSerializer, TeamSerializer, ProcessSerializer, 
 | |
|                                   RouteSerializer, TeamMemberSerializer, RoutePackSerializer,
 | |
|                                   SruleSerializer, RouteMatSerializer, RoutePackCopySerializer)
 | |
| from apps.mtm.services import get_mgroup_goals, daoru_material, get_mgroup_days
 | |
| from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
 | |
| from apps.utils.mixins import BulkCreateModelMixin, BulkDestroyModelMixin, CustomListModelMixin
 | |
| from rest_framework.serializers import Serializer
 | |
| from django.db import transaction
 | |
| from django.db.models import Q
 | |
| from apps.wf.models import Ticket
 | |
| from django.utils import timezone
 | |
| from rest_framework.permissions import IsAdminUser
 | |
| 
 | |
| # Create your views here.
 | |
| class MaterialViewSet(CustomModelViewSet):
 | |
|     """
 | |
|     list:产品
 | |
| 
 | |
|     产品
 | |
|     """
 | |
|     queryset = Material.objects.all()
 | |
|     serializer_class = MaterialSerializer
 | |
|     filterset_class = MaterialFilter
 | |
|     search_fields = ['name', 'code', 'number', 'specification', 'model']
 | |
|     select_related_fields = ['process']
 | |
|     ordering = ['name', 'model', 'specification',
 | |
|                 'type', 'process', 'process__sort', 'sort', 'id', 'number']
 | |
|     ordering_fields = ['name', 'model', 'specification',
 | |
|                        'type', 'process', 'process__sort', 'sort', 'id', 'number']
 | |
| 
 | |
|     @transaction.atomic
 | |
|     def perform_destroy(self, instance):
 | |
|         from apps.inm.models import MaterialBatch
 | |
|         if MaterialBatch.objects.filter(material=instance).exists():
 | |
|             raise ParseError('该物料有库存!')
 | |
|         if Route.objects.filter(Q(material=instance) | Q(material_in=instance) | Q(material_out=instance)).exists():
 | |
|             raise ParseError('该物料有工艺路线!')
 | |
|         instance.delete()
 | |
|         Material.objects.filter(parent=instance).update(is_deleted=True)
 | |
| 
 | |
|     @action(methods=['post'], detail=False, serializer_class=Serializer, perms_map={'post': 'material.create'})
 | |
|     @transaction.atomic
 | |
|     def daoru(self, request, *args, **kwargs):
 | |
|         """导入物料
 | |
| 
 | |
|         导入物料
 | |
|         """
 | |
|         daoru_material(settings.BASE_DIR + request.data.get('path', ''))
 | |
|         return Response()
 | |
| 
 | |
|     @action(methods=['post'], detail=True, serializer_class=Serializer, perms_map={'post': 'material.create'})
 | |
|     @transaction.atomic
 | |
|     def cal_count(self, request, *args, **kwargs):
 | |
|         """统计数量
 | |
| 
 | |
|         统计数量
 | |
|         """
 | |
|         ins = self.get_object()
 | |
|         from apps.mtm.services_2 import cal_material_count
 | |
|         cal_material_count([ins.id])
 | |
|         return Response()
 | |
| 
 | |
|     @action(methods=['put'], detail=True, serializer_class=Serializer, perms_map={'put': '*'})
 | |
|     @transaction.atomic
 | |
|     def set_week_esitimate_consume(self, request, *args, **kwargs):
 | |
|         """设置周预估消耗量
 | |
| 
 | |
|         设置周预估消耗量
 | |
|         """
 | |
|         obj: Material = self.get_object()
 | |
|         obj.week_esitimate_consume = request.data.get(
 | |
|             'week_esitimate_consume', None)
 | |
|         obj.save()
 | |
|         return Response()
 | |
|     
 | |
|     @action(methods=['get'], detail=False, serializer_class=Serializer, perms_map={'get': '*'})
 | |
|     def cates(self, request, *args, **kwargs):
 | |
|         res = Material.objects.exclude(cate='').exclude(cate=None).values_list('cate', flat=True).distinct()
 | |
|         return Response(set(res))
 | |
| 
 | |
| class ShiftViewSet(ListModelMixin, CustomGenericViewSet):
 | |
|     """
 | |
|     list:班次
 | |
| 
 | |
|     班次
 | |
|     """
 | |
|     perms_map = {'get': '*'}
 | |
|     queryset = Shift.objects.all()
 | |
|     serializer_class = ShiftSerializer
 | |
|     search_fields = ['name']
 | |
|     ordering = ['rule', 'sort', 'id']
 | |
| 
 | |
| 
 | |
| class MgroupViewSet(CustomModelViewSet):
 | |
|     """
 | |
|     list:测点集
 | |
| 
 | |
|     测点集
 | |
|     """
 | |
|     queryset = Mgroup.objects.all()
 | |
|     serializer_class = MgroupSerializer
 | |
|     select_related_fields = ['create_by', 'belong_dept', 'process']
 | |
|     filterset_fields = {
 | |
|         "belong_dept": ["exact"],
 | |
|         "process": ["exact"],
 | |
|         "cate": ["exact"],
 | |
|         "belong_dept__name": ["exact", "contains"],
 | |
|         "name": ["exact", "contains"],
 | |
|         "code": ["exact", "in", "isnull"]
 | |
|     }
 | |
|     search_fields = ['name']
 | |
|     ordering = ['sort', 'create_time']
 | |
| 
 | |
|     def perform_destroy(self, instance):
 | |
|         Route.objects.filter(
 | |
|             mgroup=instance, material__need_route=False).delete()
 | |
|         Route.objects.filter(mgroup=instance).update(mgroup=None)
 | |
|         instance.delete()
 | |
|     
 | |
|     @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=MgroupDaysSerializer)
 | |
|     def get_days(self, request):
 | |
|         """
 | |
|         获取所属班年月日
 | |
| 
 | |
|         给定一个时间获取所属班年月日
 | |
|         """
 | |
|         data = request.data
 | |
|         sr = MgroupDaysSerializer(data=data)
 | |
|         sr.is_valid(raise_exception=True)
 | |
|         vdata = sr.validated_data
 | |
|         mgroup = Mgroup.objects.get(id=vdata["mgroup"])
 | |
|         return Response(get_mgroup_days(mgroup, vdata.get("now", None)))
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| class TeamViewSet(CustomModelViewSet):
 | |
|     """
 | |
|     list:班组
 | |
| 
 | |
|     班组
 | |
|     """
 | |
|     queryset = Team.objects.all()
 | |
|     serializer_class = TeamSerializer
 | |
|     select_related_fields = ['belong_dept', 'leader']
 | |
|     filterset_fields = ['belong_dept']
 | |
|     search_fields = ['rule']
 | |
| 
 | |
| 
 | |
| class TeamMemberViewSet(ListModelMixin, BulkCreateModelMixin, BulkDestroyModelMixin, CustomGenericViewSet):
 | |
|     """
 | |
|     list: 班组成员
 | |
| 
 | |
|     班组成员
 | |
|     """
 | |
|     perms_map = {'get': '*', 'post': 'team.update', 'delete': 'team.delete'}
 | |
|     queryset = TeamMember.objects.all()
 | |
|     serializer_class = TeamMemberSerializer
 | |
|     select_related_fields = ['mgroup', 'post', 'team', 'user']
 | |
|     filterset_fields = ['mgroup', 'post', 'team']
 | |
| 
 | |
| 
 | |
| class GoalViewSet(CustomModelViewSet):
 | |
|     """
 | |
|     list: 目标
 | |
| 
 | |
|     目标
 | |
|     """
 | |
|     queryset = Goal.objects.all()
 | |
|     serializer_class = GoalSerializer
 | |
|     select_related_fields = ['mgroup', 'goal_cate']
 | |
|     filterset_class = GoalFilter
 | |
|     search_fields = ['name']
 | |
|     ordering = ['mgroup__sort', 'goal_cate__sort', 'goal_cate__create_time']
 | |
| 
 | |
|     @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=MgroupGoalYearSerializer)
 | |
|     def mgroup_goals_year(self, request, pk=None):
 | |
|         """
 | |
|         获取工段全年目标
 | |
| 
 | |
|         获取工段全年目标
 | |
|         """
 | |
|         sr = MgroupGoalYearSerializer(data=request.data)
 | |
|         sr.is_valid(raise_exception=True)
 | |
|         vdata = sr.validated_data
 | |
|         res = get_mgroup_goals(vdata['mgroup'], vdata['year'], True)
 | |
|         return Response(res)
 | |
| 
 | |
| 
 | |
| class ProcessViewSet(CustomModelViewSet):
 | |
|     queryset = Process.objects.all()
 | |
|     serializer_class = ProcessSerializer
 | |
|     select_related_fields = ['belong_dept']
 | |
|     search_fields = ['name', 'cate']
 | |
|     filterset_fields = {
 | |
|         "cate": ['exact'],
 | |
|         "parent": ['isnull', "exact"]
 | |
|     }
 | |
|     ordering = ['sort', 'create_time']
 | |
| 
 | |
|     def perform_destroy(self, instance):
 | |
|         if Route.objects.filter(process=instance).exists():
 | |
|             raise ParseError('存在使用的工艺路线!')
 | |
|         return super().perform_destroy(instance)
 | |
| 
 | |
| 
 | |
| 
 | |
| class RoutePackViewSet(CustomModelViewSet):
 | |
|     """
 | |
|     list: 工艺路线包
 | |
| 
 | |
|     工艺路线包
 | |
|     """
 | |
|     queryset = RoutePack.objects.all()
 | |
|     serializer_class = RoutePackSerializer
 | |
|     search_fields = ['name']
 | |
|     select_related_fields = ['material', 'create_by', "document"]
 | |
|     filterset_fields = ['material', 'state']
 | |
| 
 | |
|     def update(self, request, *args, **kwargs):
 | |
|         obj: RoutePack = self.get_object()
 | |
|         if obj.state != RoutePack.RP_S_CREATE:
 | |
|             raise ParseError('该状态下不可编辑')
 | |
|         return super().update(request, *args, **kwargs)
 | |
| 
 | |
|     @transaction.atomic
 | |
|     def destroy(self, request, *args, **kwargs):
 | |
|         obj: RoutePack = self.get_object()
 | |
|         if obj.state != RoutePack.RP_S_CREATE:
 | |
|             raise ParseError('该状态下不可删除')
 | |
|         obj.delete()
 | |
|         Ticket.objects.filter(ticket_data__t_id=obj.id, ticket_data__t_model='routepack').delete()
 | |
|         return Response(status=204)
 | |
|     
 | |
|     @transaction.atomic
 | |
|     @action(methods=['post'], detail=False, perms_map={'post': 'routepack.create'}, serializer_class=RoutePackCopySerializer)
 | |
|     def copy(self, request, *args, **kwargs):
 | |
|         """复制工艺路线
 | |
| 
 | |
|         复制工艺路线
 | |
|         """
 | |
|         data = request.data
 | |
|         sr = RoutePackCopySerializer(data=data)
 | |
|         sr.is_valid(raise_exception=True)
 | |
|         vdata = sr.validated_data
 | |
|         user = request.user
 | |
|         now = timezone.now()
 | |
|         new_name = vdata["new_name"]
 | |
|         rp = RoutePack.objects.get(id=vdata["routepack"])
 | |
|         matin = Material.objects.get(id=vdata["material_in"])
 | |
|         matout = Material.objects.get(id=vdata["material_out"])
 | |
|         obj_c = RoutePack()
 | |
|         obj_c.name = new_name
 | |
|         obj_c.material = matout
 | |
|         obj_c.create_by = user
 | |
|         obj_c.create_time = now
 | |
|         obj_c.save()
 | |
|         genM = {}
 | |
|         for ind, route in enumerate(Route.get_routes(routepack=rp)):
 | |
|             route_new = Route()
 | |
|             process = route.process
 | |
|             for f in Route._meta.fields:
 | |
|                 if f.name in ['process', 'sort', 'is_autotask', 'is_count_utask', 'out_rate', 'div_number', 'hour_work', 'batch_bind']:
 | |
|                     setattr(route_new, f.name, getattr(route, f.name, None))
 | |
|             route_new.material = matout
 | |
|             # material_out = RouteSerializer.gen_material_out(instance=route_new, material_out_tracking=route.material_out.tracking)
 | |
|             # route_new.material_out = material_out
 | |
|             # if ind == 0:
 | |
|             #     route_new.material_in = matin
 | |
|             # elif route.material_in.process and route.material_in.process.id in genM:
 | |
|             #     route_new.material_in = genM[route.material_in.process.id]
 | |
|             # genM[process.id] = material_out
 | |
|             route_new.routepack = obj_c
 | |
|             route_new.create_by = user
 | |
|             route_new.create_time = now
 | |
|             route_new.save()
 | |
|             for rm in RouteMat.objects.filter(route=route):
 | |
|                 rm_new = RouteMat()
 | |
|                 rm_new.route = route_new
 | |
|                 rm_new.material = rm.material
 | |
|                 rm_new.save()
 | |
|         return Response({"id": route_new.id})
 | |
|     
 | |
|     @transaction.atomic
 | |
|     @action(methods=['post'], detail=True, permission_classes = [IsAdminUser], serializer_class=Serializer)
 | |
|     def toggle_state(self, request, *args, **kwargs):
 | |
|         """变更工艺路线状态
 | |
| 
 | |
|         变更工艺路线状态
 | |
|         """
 | |
|         ins:RoutePack = self.get_object()
 | |
|         if  ins.state == RoutePack.RP_S_CONFIRM:
 | |
|             ins.state = RoutePack.RP_S_CREATE
 | |
|         elif ins.state == RoutePack.RP_S_CREATE:
 | |
|             if ins.ticket is not None:
 | |
|                 ins.get_gjson(need_update=True)
 | |
|                 ins.state = RoutePack.RP_S_CONFIRM
 | |
|             else:
 | |
|                 raise ParseError("该路线未提交审核")
 | |
|         else:
 | |
|             raise ParseError("该状态下不可变更")
 | |
|         ins.save()
 | |
|         return Response()
 | |
| 
 | |
|     @action(methods=['get'], detail=True, perms_map={'get': '*'})
 | |
|     def dag(self, request, *args, **kwargs):
 | |
|         """获取总图
 | |
| 
 | |
|         获取总图
 | |
|         """
 | |
|         return Response(Route.get_dag(rqs=Route.objects.filter(routepack=self.get_object())))
 | |
|     
 | |
|     @action(methods=['get'], detail=True, perms_map={'get': '*'})
 | |
|     def dags(self, request, *args, **kwargs):
 | |
|         """获取所有子图
 | |
| 
 | |
|         获取所有子图
 | |
|         """
 | |
|         ins = self.get_object()
 | |
|         return Response(ins.get_dags())
 | |
|     
 | |
|     @action(methods=['get'], detail=True, perms_map={'get': '*'})
 | |
|     def final_materials(self, request, *args, **kwargs):
 | |
|         """获取最终产品
 | |
|         
 | |
|         获取最终产品"""
 | |
|         ins:RoutePack = self.get_object()
 | |
|         matIds = ins.get_final_material_ids()
 | |
|         qs = Material.objects.filter(id__in=matIds)
 | |
|         res = [{"id": x.id, "name": str(x)} for x in qs]
 | |
|         return Response(res)
 | |
| class RouteViewSet(CustomModelViewSet):
 | |
|     queryset = Route.objects.all()
 | |
|     serializer_class = RouteSerializer
 | |
|     filterset_class = RouteFilter
 | |
|     ordering = ['sort', 'process__sort', 'create_time']
 | |
|     ordering_fields = ['sort', 'process__sort', 'create_time', 'update_time']
 | |
|     select_related_fields = ['material',
 | |
|                              'process', 'material_in', 'material_out', 'mgroup', 'routepack']
 | |
| 
 | |
|     def update(self, request, *args, **kwargs):
 | |
|         obj:Route = self.get_object()
 | |
|         routepack = obj.routepack
 | |
|         if routepack and routepack.state != RoutePack.RP_S_CREATE:
 | |
|             raise ParseError('该状态下不可编辑')
 | |
|         return super().update(request, *args, **kwargs)
 | |
| 
 | |
| 
 | |
| class SruleViewSet(CustomModelViewSet):
 | |
|     """
 | |
|     list: 排班规则
 | |
|     """
 | |
|     queryset = Srule.objects.all()
 | |
|     serializer_class = SruleSerializer
 | |
|     select_related_fields = ['belong_dept']
 | |
|     filterset_fields = ['belong_dept']
 | |
|     search_fields = ['belong_dept__name']
 | |
|     
 | |
|     def add_info_for_list(self, data):
 | |
|         rule_list = [x['rule'] for x in data]
 | |
|         teamIds = []
 | |
|         for rule in rule_list:
 | |
|             teamIds.extend(rule)
 | |
|         teams = Team.objects.filter(id__in=teamIds).values_list('id', 'name')
 | |
|         teams_dict = dict(teams)
 | |
|         for item in data:
 | |
|             rule = item["rule"]
 | |
|             item["rule_display"] = "->".join([teams_dict.get(x, '未知') for x in rule])
 | |
|         return data
 | |
| 
 | |
| class RouteMatViewSet(CustomListModelMixin, BulkCreateModelMixin, BulkDestroyModelMixin, CustomGenericViewSet):
 | |
|     perms_map = {"get": "*", "post": "route.update", "delete": "route.update"}
 | |
|     queryset = RouteMat.objects.all()
 | |
|     serializer_class = RouteMatSerializer
 | |
|     filterset_fields = ['route', 'material'] |