hberp/hb_server/apps/pm/views.py

429 lines
19 KiB
Python

from datetime import timezone
from typing import List
from django.db import transaction
from rest_framework import serializers
from rest_framework.views import APIView
from apps.em.models import Equipment
from apps.em.serializers import EquipmentSimpleSerializer
from apps.hrm.services import HRMService
from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import Material, RecordFormField, Step, SubProduction, SubprodctionMaterial
from apps.pm.filters import PlanFilterSet, SubproductionProgressFilterSet
from apps.qm.models import TestRecord, TestRecordItem
from apps.qm.serializers import TestRecordDetailBaseSerializer
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import FirstTestAuditSerializer, FirstTestInitSerializer, GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, ResourceConvertListSerializer, ResourceConvertSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from django.shortcuts import render
from apps.sam.models import Order
from rest_framework.exceptions import APIException, ParseError, ValidationError
from rest_framework.response import Response
from rest_framework.decorators import action
from django.db.models import F
from apps.system.serializers import UserSimpleSerializer
from utils.tools import ranstr
from django.db import transaction
from rest_framework import status
from django.utils import timezone
# Create your views here.
def updateOrderPlanedCount(order):
"""
更新订单已排数量
"""
planed_count = 0
plans = ProductionPlan.objects.filter(order=order)
for i in plans:
planed_count = planed_count + i.count
order.planed_count = planed_count
order.save()
class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModelMixin, RetrieveModelMixin, GenericViewSet):
"""
生产计划
"""
perms_map = {'get': '*', 'post':'plan_create'}
queryset = ProductionPlan.objects.select_related('order', 'order__contract', 'product')
serializer_class = ProductionPlanSerializer
search_fields = ['number', 'order__number', 'order__contract__number', 'product__number']
filterset_class = PlanFilterSet
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action in ['create']:
return ProductionPlanCreateFromOrderSerializer
elif self.action == 'list':
return ProductionPlanSerializer
return super().get_serializer_class()
@transaction.atomic()
def create(self, request, *args, **kwargs):
data = request.data
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
if data.get('order', None):
order = Order.objects.get(pk=data['order'])
if order.planed_count >= data['count'] or data['count'] > 0:
pass
else:
raise APIException('排产数量错误')
instance = serializer.save(create_by=request.user, product=order.product, number='JH'+ranstr(7))
updateOrderPlanedCount(instance.order)
return Response()
@action(methods=['post'], detail=False, perms_map={'post':'plan_delete'}, serializer_class=PlanDestorySerializer)
def deletes(self, request, pk=None):
"""
批量物理删除
"""
ProductionPlan.objects.filter(id__in=request.data.get('ids', [])).delete(soft=False)
return Response()
@action(methods=['post'], detail=True, perms_map={'post':'gen_subplan'}, serializer_class=GenSubPlanSerializer)
@transaction.atomic
def gen_subplan(self, request, pk=None):
"""
生成子计划
"""
production_plan=self.get_object()
if production_plan.is_planed:
raise APIException('已生成子计划')
if production_plan.state != ProductionPlan.PLAN_STATE_PLANING:
raise APIException('不可操作')
subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number')
for index, i in enumerate(subps):
steps = Step.objects.filter(usedstep__subproduction=i, usedstep__subproduction__is_deleted=False,
usedstep__is_deleted=False, is_deleted=False
).order_by('number').values('id', 'number', 'name', 'usedstep__remark', need_test=F('usedstep__need_test'))
instance = SubProductionPlan.objects.create(production_plan=production_plan, subproduction=i,
start_date=production_plan.start_date, end_date=production_plan.end_date,
workshop=i.process.workshop, process=i.process, create_by=request.user,
steps = list(steps), number=production_plan.number + '-' + str(index+1))
# 生成子计划物料需求/进度
for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
spro = SubProductionProgress.objects.create(material=m.material, type=m.type,
is_main=m.is_main,
count=m.count*production_plan.count, subproduction_plan=instance)
production_plan.is_planed=True
production_plan.save()
return Response()
@action(methods=['put'], detail=True, perms_map={'post':'plan_toggle'}, serializer_class=serializers.Serializer)
@transaction.atomic
def toggle(self, request, pk=None):
"""
计划暂停或启动
"""
plan = self.get_object()
if plan.state == ProductionPlan.PLAN_STATE_PAUSE:
plan.state = plan.old_state
plan.old_state = None
plan.save()
return Response()
elif plan.state <= ProductionPlan.PLAN_STATE_WORKING:
plan.old_state = plan.state
plan.state = ProductionPlan.PLAN_STATE_PAUSE
plan.save()
return Response()
raise APIException('不可操作')
@action(methods=['put'], detail=True, perms_map={'post':'plan_stop'}, serializer_class=serializers.Serializer)
@transaction.atomic
def stop(self, request, pk=None):
"""
计划终止
"""
plan = self.get_object()
if plan.state == ProductionPlan.PLAN_STATE_PAUSE:
plan.state = ProductionPlan.PLAN_STATE_STOP
plan.save()
return Response()
raise APIException('不可操作')
class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateModelMixin, GenericViewSet):
"""
子生产计划-列表/修改
"""
perms_map = {'get': '*', 'put':'subplan_update'}
queryset = SubProductionPlan.objects.select_related('process',
'workshop', 'subproduction', 'product',
'production_plan__product', 'leader_1', 'leader_2', 'leader_3', 'first_test')
search_fields = []
serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan', 'process', 'state', 'product', 'workshop']
ordering_fields = ['process__number']
ordering = ['process__number']
def get_serializer_class(self):
if self.action == 'list':
return SubProductionPlanListSerializer
elif self.action == 'update':
return SubProductionPlanUpdateSerializer
return super().get_serializer_class()
@action(methods=['get'], detail=True, perms_map={'get':'*'}, serializer_class=SubProductionProgressSerializer)
def progress(self, request, pk=None):
"""
生产进度详情
"""
obj = self.get_object()
serializer = SubProductionProgressSerializer(instance=obj.progress_subplan, many=True)
return Response(serializer.data)
@action(methods=['post'], detail=True, perms_map={'post':'subplan_issue'}, serializer_class=serializers.Serializer)
@transaction.atomic
def issue(self, request, pk=None):
"""
下达任务
"""
obj = self.get_object()
if obj.state == SubProductionPlan.SUBPLAN_STATE_PLANING:
obj.state = SubProductionPlan.SUBPLAN_STATE_ASSGINED
obj.save()
plan = obj.production_plan
if plan.state == ProductionPlan.PLAN_STATE_PLANING:
plan.state = ProductionPlan.PLAN_STATE_ASSGINED
plan.save()
return Response()
raise APIException('计划状态有误')
@action(methods=['post'], detail=True, perms_map={'post':'subplan_start'}, serializer_class=serializers.Serializer)
def start(self, request, pk=None):
"""
开始生产
"""
obj = self.get_object()
if obj.state in [SubProductionPlan.SUBPLAN_STATE_ASSGINED, SubProductionPlan.SUBPLAN_STATE_ACCEPTED]:
obj.state = SubProductionPlan.SUBPLAN_STATE_WORKING
obj.start_date_real = timezone.now()
obj.save()
plan = obj.production_plan
if plan.state in [ProductionPlan.PLAN_STATE_ASSGINED, ProductionPlan.PLAN_STATE_ACCEPTED]:
plan.state = ProductionPlan.PLAN_STATE_WORKING
plan.save()
return Response()
raise APIException('计划状态有误')
@action(methods=['get'], detail=True, perms_map={'get':'*'}, serializer_class=serializers.Serializer)
def pick_need_(self, request, pk=None):
"""
领料需求清单
"""
obj = self.get_object()
instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
serializer = SubProductionProgressSerializer(instance=instance, many=True)
return Response(serializer.data)
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
def pick_need(self, request, pk=None):
"""
领料需求清单/库存数
"""
obj = self.get_object()
instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
serializer = SubProductionProgressSerializer(instance=instance, many=True)
need = serializer.data
materials = []
for i in need:
materials.append(i['material'])
objs = MaterialBatch.objects.filter(material__id__in=materials, count__gt=0).order_by('material__number')
have = MaterialBatchSerializer(instance=objs, many=True).data
return Response({'need':need, 'have':have})
@action(methods=['post'], detail=True, perms_map={'post':'first_test'}, serializer_class=FirstTestInitSerializer)
@transaction.atomic
def first_test_init(self, request, pk=None):
"""
首件检查表初始化
"""
obj = self.get_object()
first_test = obj.first_test
if first_test:
return Response(TestRecordDetailBaseSerializer(instance=first_test).data)
else:
rdata = request.data
serializer = self.get_serializer(data=rdata)
serializer.is_valid(raise_exception=True)
form = serializer.validated_data.get('form')
savedict = dict(
create_by=request.user,
subproduction_plan=obj,
type = TestRecord.TEST_FIRST,
form=form)
tr = TestRecord.objects.create(**savedict)
for i in RecordFormField.objects.filter(form=form, is_deleted=False):
tri = TestRecordItem()
tri.test_record = tr
tri.form_field = i
tri.is_hidden = i.is_hidden
tri.create_by = request.user
tri.save()
obj.first_test = tr
obj.save()
return Response(TestRecordDetailBaseSerializer(instance=tr).data)
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=FirstTestAuditSerializer)
@transaction.atomic
def first_audit(self, request, pk=None):
"""
首件审核
"""
obj = self.get_object()
if obj.leader_1 and obj.leader_2 and obj.leader_3:
raise ValidationError('首件确认已完成')
if obj.first_test is None:
raise ValidationError('未进行首件检查')
if not obj.first_test.is_submited:
raise ValidationError('首件检查未提交')
if not obj.first_test.is_testok:
raise ValidationError('首件检查不合格')
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
le = vdata.get('leader')
if le not in ['leader_1', 'leader_2', 'leader_3']:
return Response('审核人有误', status=status.HTTP_400_BAD_REQUEST)
if vdata.get('leader') == 'leader_1':
obj.leader_1 = request.user
elif vdata.get('leader') == 'leader_2':
obj.leader_2 = request.user
else:
obj.leader_3 = request.user
obj.first_sign_time = timezone.now()
obj.save()
return Response(UserSimpleSerializer(instance=request.user).data)
class SubProductionProgressViewSet(ListModelMixin, GenericViewSet):
"""
生产进度
"""
perms_map = {'get': '*'}
queryset = SubProductionProgress.objects.select_related('material', 'subproduction_plan')
search_fields = []
serializer_class = SubProductionProgressSerializer
filterset_class = SubproductionProgressFilterSet
ordering_fields = ['id']
ordering = ['id']
class ResourceViewSet(GenericViewSet):
perms_map = {'*': '*'}
@action(methods=['post'], detail=False, perms_map={'post':'resource_cal'}, serializer_class=ResourceCalListSerializer)
def cal(self, request, pk=None):
"""
物料消耗计算
"""
rdata = request.data
serializer = self.get_serializer(data=rdata)
serializer.is_valid(raise_exception=True)
productIdList = []
productList = []
for i in rdata:
if i['id'] not in productIdList:
productIdList.append(i['id'])
productList.append(i)
else:
index = productIdList.index(i['id'])
productList[index]['count'] = productList[index]['count'] + i['count']
res_d_list = []
res = []
for i in productList:
# 计算输入物料
materials = SubprodctionMaterial.objects.filter(subproduction__product__id=i['id'],
subproduction__is_deleted=False, is_deleted=False,
type= SubprodctionMaterial.SUB_MA_TYPE_IN).order_by(
'material__type', 'material__number')\
.values('material__id', 'material__name',
'material__number', 'material__type',
'count', 'material__count', 'material__count_safe')
l_m = list(materials)
for m in l_m:
if m['material__id'] in res_d_list:
if m['material__type'] in [Material.MA_TYPE_MAINSO, Material.MA_TYPE_HELPSO]:
index = res_d_list.index(m['material__id'])
res[index]['count'] = res[index]['count'] + m['count']*i['count']
else:
res_d_list.append(m['material__id'])
item = {'id':m['material__id'], 'name':m['material__name'],
'type':m['material__type'], 'number':m['material__number'],
'count': None,'inv_count':m['material__count'],
'count_safe':m['material__count_safe']}
if item['type'] in [Material.MA_TYPE_MAINSO, Material.MA_TYPE_HELPSO]:
item['count'] = m['count']*i['count']
res.append(item)
return Response(res)
@action(methods=['post'], detail=False, perms_map={'post':'resource_cal'}, serializer_class=ResourceConvertListSerializer)
def convert(self, request, pk=None):
rdata = request.data
serializer = self.get_serializer(data=rdata)
serializer.is_valid(raise_exception=True)
res_d_list = []
res = []
half_list = rdata
while half_list:
fitem = half_list[0]
sm = SubprodctionMaterial.objects.filter(
type= SubprodctionMaterial.SUB_MA_TYPE_OUT,
is_deleted = False,
material__id = fitem['id']
).first()
if sm:
spn = sm.subproduction
sm_left_l = list(SubprodctionMaterial.objects.filter(
subproduction = spn,
type= SubprodctionMaterial.SUB_MA_TYPE_IN,
is_deleted = False,
).order_by('material__number')\
.values('material__id', 'material__name',
'material__number', 'material__type',
'count', 'material__count', 'material__count_safe'))
for i in sm_left_l:
if i['material__type'] == Material.MA_TYPE_HALFGOOD:
item = {
'id':i['material__id'],
'count':(i['count']*fitem['count'])/(sm.count)
}
half_list.append(item)
else:
if i['material__id'] in res_d_list:
index = res_d_list.index(i['material__id'])
res[index]['count'] = res[index]['count'] + \
(i['count']*fitem['count'])/(sm.count)
else:
res_d_list.append(i['material__id'])
item = {
'id': i['material__id'],
'count':(i['count']*fitem['count'])/(sm.count)
}
res.append(item)
del(half_list[0])
return Response(res)
@action(methods=['post'], detail=False, perms_map={'post':'resource_cal'}, serializer_class=ResourceCalListSerializer)
def cal_equip(self, request, pk=None):
"""
设备状态查看
"""
rdata = request.data
serializer = self.get_serializer(data=rdata)
serializer.is_valid(raise_exception=True)
rdata_l = []
for i in rdata:
rdata_l.append(i['id'])
subproductions = SubProduction.objects.filter(product__id__in=rdata_l, is_deleted=False)
steps = Step.objects.filter(usedstep__is_deleted=False, usedstep__subproduction__in=subproductions)
equips = Equipment.objects.filter(step_equips__in=steps, is_deleted=False).distinct()
serializer = EquipmentSimpleSerializer(instance=equips, many=True)
return Response(serializer.data)