from django.shortcuts import render from rest_framework.generics import CreateAPIView, GenericAPIView from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.utils import serializer_helpers from rest_framework.utils.field_mapping import get_relation_kwargs from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet, ModelViewSet from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse from apps.inm.signals import update_inm from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial, TechDoc from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from apps.qm.models import TestRecordItem from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers from apps.wpm.services import WpmServies from django.utils import timezone from utils.tools import ranstr # Create your views here. class WPlanViewSet(ListModelMixin, GenericViewSet): """ 车间生产计划 """ perms_map = {'*': '*'} queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'main_product').exclude(state=0) search_fields = [] serializer_class = SubProductionPlanListSerializer filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop'] ordering_fields = [] ordering = ['-id'] @action(methods=['post', 'get'], detail=True, perms_map={'post':'*', 'get':'*'}, serializer_class=PickHalfSerializer) @transaction.atomic def pick_half(self, request, pk=None): """ 领半成品 """ sp = self.get_object() if request.method=='GET': """ 领半成品 """ spps = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN, material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material') return Response(SubProductionProgressSerializer(instance=spps, many=True).data) elif request.method=='POST': serializer= PickHalfSerializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) vdata = serializer.data first_step = Step.objects.get(pk=sp.steps[0]['id']) for i in vdata: if 'wproducts' in i and len(i['wproducts'])>0: spp = SubProductionProgress.objects.get(pk=i['id']) spp.count_pick = spp.count_pick + len(i['wproducts']) if spp.count_pick > spp.count: raise exceptions.APIException('超过计划数') spp.save() wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']]) wps.update(step=first_step, is_executed=False, act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None, subproduction_plan=sp, production_plan=sp.production_plan, update_by=request.user, update_time=timezone.now()) return Response() @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WplanPutInSerializer) @transaction.atomic def putin(self, request, pk=None): """ 半成品入库 """ serializer= WplanPutInSerializer(data=request.data) serializer.is_valid(raise_exception=True) vdata = serializer.data subplan = self.get_object() material = subplan.main_product batch = subplan.production_plan.number warehouse = WareHouse.objects.get(id=vdata['warehouse']) wproducts = WProduct.objects.filter(subproduction_plan=subplan, act_state=WProduct.WPR_ACT_STATE_OK, material=material, is_deleted=False) if wproducts.exists(): # 创建入库记录 remark = vdata.get('remark', '') fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN, is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark) # 创建入库明细 fifoitem = FIFOItem() fifoitem.is_tested = True fifoitem.is_testok = True fifoitem.warehouse = warehouse fifoitem.material = material fifoitem.count = wproducts.count() fifoitem.batch = batch fifoitem.fifo = fifo fifoitem.subproduction_plan = subplan fifoitem.save() # 创建入库明细半成品 ips = [] for i in wproducts: ip = {} ip['fifoitem'] = fifoitem ip['wproduct'] = i ip['number'] = i.number ip['material'] = material ips.append(FIFOItemProduct(**ip)) FIFOItemProduct.objects.bulk_create(ips) # 创建IProduct ips2 = [] for i in wproducts: ip = {} ip['warehouse'] = warehouse ip['batch'] = batch ip['wproduct'] = i ip['number'] = i.number ip['material'] = material ips2.append(IProduct(**ip)) IProduct.objects.bulk_create(ips2) # 更新库存并修改半成品进行状态 update_inm(fifo) wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user, update_time=timezone.now()) return Response() class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet): """ 车间物料表 """ perms_map={'*':'*'} queryset = WMaterial.objects.select_related('material').all() serializer_class = WMaterialListSerializer filterset_fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop'] ordering_fields = ['material__number'] ordering = ['material__number'] @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PickSerializer) def pick(self, request, pk=None): """ 领料 """ serializer= PickSerializer(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) serializer.save() return Response() class WProductViewSet(ListModelMixin, GenericViewSet): """ 半成品 """ perms_map={'*':'*'} queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False).exclude(operation=None) serializer_class = WProductListSerializer filterset_fields = ['step', 'subproduction_plan', 'material', 'production_plan', 'step__process', 'act_state'] search_fields = ['number'] ordering_fields = ['id'] ordering = ['id'] @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer) @transaction.atomic def test(self, request, pk=None): """ 检测 """ serializer = WpmTestRecordCreateSerializer(data=request.data) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data record_data = vdata.pop('record_data') wproduct = vdata['wproduct'] if wproduct.act_state != WProduct.WPR_ACT_STATE_TOTEST: raise exceptions.APIException('该半成品不可检测') if 'is_testok' not in vdata: raise exceptions.APIException('未填写检测结论') obj = serializer.save(create_by = self.request.user, material=wproduct.material) tris = [] for m in record_data: # 保存记录详情 form_field = m['form_field'] m['field_name'] = form_field.field_name m['field_key'] = form_field.field_key m['field_type'] = form_field.field_type m['field_value'] = m['field_value'] m['sort'] = form_field.sort m['need_judge'] = form_field.need_judge m['is_testok'] = m['is_testok'] if 'is_testok' in m else None m['test_record'] = obj tris.append(TestRecordItem(**m)) TestRecordItem.objects.bulk_create(tris) # 如果检测合格, 变更动态产品进行状态 if obj.is_testok: wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.number is None: # 产生半成品编号 wproduct.number = 'WP'+ranstr(7) wproduct.save() # 更新子计划状态 # 更新子计划主产品数 instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) instance.count_real = instance.count_real + 1 # 这个地方可能会有问题 instance.save() else:# 如果不合格 pass return Response() @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer) @transaction.atomic def putin(self, request, pk=None): """ 半成品入库 """ serializer= WproductPutInSerializer(data=request.data) serializer.is_valid(raise_exception=True) vdata = serializer.data wproduct = self.get_object() warehouse = WareHouse.objects.get(id=vdata['warehouse']) if wproduct.act_state != WProduct.WPR_ACT_STATE_OK: raise exceptions.APIException('半成品不可入库') material = wproduct.material batch = wproduct.production_plan.number # 创建入库记录 remark = vdata.get('remark', '') fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN, is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark) # 创建入库明细 fifoitem = FIFOItem() fifoitem.is_tested = True fifoitem.is_testok = True fifoitem.warehouse = warehouse fifoitem.material = material fifoitem.count = 1 # 单个半成品入库 fifoitem.batch = batch fifoitem.fifo = fifo fifoitem.subproduction_plan = wproduct.subproduction_plan fifoitem.save() # 创建入库明细半成品 ips = [] for i in [wproduct]: ip = {} ip['fifoitem'] = fifoitem ip['wproduct'] = i ip['number'] = i.number ip['material'] = material ips.append(FIFOItemProduct(**ip)) FIFOItemProduct.objects.bulk_create(ips) # 更新库存并修改半成品进行状态 update_inm(fifo) wproduct.act_state=WProduct.WPR_ACT_STATE_INM wproduct.warehouse=warehouse wproduct.save() return Response() class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, GenericViewSet): """ 生产操作记录 """ perms_map={'*':'*'} queryset = Operation.objects.select_related('step').prefetch_related('ow_operation', 'oe_operation', 'or_operation').all() serializer_class = OperationListSerializer filterset_fields = ['step', 'step__process', 'is_submited'] ordering_fields = ['id'] ordering = ['-id'] def get_queryset(self): return self.queryset.filter(create_by=self.request.user) def get_serializer_class(self): if self.action == 'retrieve': return OperationDetailSerializer elif self.action == 'create': return OperationCreateSerializer elif self.action == 'update': return OperationUpdateSerializer return super().get_serializer_class() @transaction.atomic def create(self, request, *args, **kwargs): data = request.data serializer = OperationCreateSerializer(data=data, context={'request':self.request}) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data #校验之后的数据 step = vdata['step'] op = Operation() op.step = step op.is_submited = False op.create_by = request.user op.save() # 创建操作所用半成品关联记录 if 'wproducts' in vdata: owps = [] for wpd in vdata['wproducts']: owp = {} owp['operation'] = op owp['wproduct'] = wpd owp['number'] = wpd.number owp['material'] = wpd.material owp['subproduction_plan'] = wpd.subproduction_plan owp['production_plan'] = wpd.production_plan owps.append(OperationWproduct(**owp)) OperationWproduct.objects.bulk_create(owps) # 查询需要填写的自定义表格 forms = RecordForm.objects.filter(step=step, type=RecordForm.RF_TYPE_DO) for i in forms: opr = OperationRecord() opr.operation = op opr.form = i opr.is_filled = False opr.save() # 查询需要使用的生产设备 for i in step.equipments.all(): ope = OperationEquip() ope.operation = op ope.equip = i ope.save() return Response() class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): """ 操作使用的半成品 """ perms_map={'*':'*'} queryset = OperationWproduct.objects.select_related('subproduction_plan', 'material').all() serializer_class = OperationWproductListSerializer filterset_fields = ['material', 'subproduction_plan', 'operation'] ordering_fields = ['id'] ordering = ['-id'] @transaction.atomic() def destroy(self, request, *args, **kwargs): instance = self.get_object() if instance.operation.is_submited: raise exceptions.APIException('该操作已提交') instance.delete() wp = instance.wproduct wp.operation = None wp.save() return Response() class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet): """ 操作使用的设备 """ perms_map={'*':'*'} queryset = OperationEquip.objects.select_related('operation', 'equip').all() serializer_class = OperationEquipListSerializer filterset_fields = ['operation', 'equip'] ordering_fields = ['id'] ordering = ['-id'] def get_serializer_class(self): if self.action == 'update': return OperationEquipUpdateSerializer return super().get_serializer_class() @transaction.atomic() def destroy(self, request, *args, **kwargs): instance = self.get_object() if instance.operation.is_submited: raise exceptions.APIException('该操作已提交') instance.delete() return Response() class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): """ 操作使用的自定义表格 """ perms_map={'*':'*'} queryset = OperationRecord.objects.select_related('operation', 'form').all() serializer_class = OperationRecordListSerializer filterset_fields = ['operation', 'form'] ordering_fields = ['id'] ordering = ['-id'] @transaction.atomic() def destroy(self, request, *args, **kwargs): instance = self.get_object() if instance.operation.is_submited: raise exceptions.APIException('该操作已提交') instance.delete() return Response() @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=OperationRecordSubmitSerializer) def submit(self, request, pk=None): serializer = OperationRecordSubmitSerializer(data=request.data, context={'request':self.request}) serializer.is_valid(raise_exception=True) vdata = serializer.data opr = self.get_object() wrds = [] for m in vdata['record_data']: # 保存记录详情 form_field = m['form_field'] m['field_name'] = form_field.field_name m['field_key'] = form_field.field_key m['field_type'] = form_field.field_type m['field_value'] = m['field_value'] m['sort'] = form_field.sort m['operation_record'] = opr wrds.append(OperationRecordItem(**m)) OperationRecordItem.objects.bulk_create(wrds) opr.is_filled = True opr.save() return Response() class DoFormInit(CreateAPIView, GenericAPIView): perms_map={'*':'*'} serializer_class=OperationInitSerializer def post(self, request, format=None): """ 调用操作表单 """ data = request.data serializer = OperationInitSerializer(data=data) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data ret = {} ret_0 = {} ret_0['step'] = data['step'] splans =[] ret_0['input'] = [] # ret_0['subproduction_plan'] = data['subproduction_plan'] if 'wproducts' in data and data['wproducts']: ret_0['wproducts'] = data['wproducts'] splans = WProduct.objects.filter(id__in=data['wproducts']).values_list('subproduction_plan', flat=True) # 调出所属子计划现有物料 ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(subproduction_plan__in=splans), many=True).data else: if 'subproduction_plan' in vdata: splans = [vdata['subproduction_plan']] else: splans = SubProductionPlan.objects.filter(is_deleted=False, subproduction__usedstep_subproduction__step=vdata['step'], state=3) ret_0['wproducts'] = [] ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(subproduction_plan__in=splans), many=True).data for i in ret_0['input']: i['count_input'] = 0 # 需要输出的物料 if ret_0['wproducts']: # 排除主要产物, 因为已经放到半成品里了, 由半成品进行处理, 夹层可能需要特殊处理 o_objs = SubProductionProgress.objects.filter( subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT).exclude(is_main=True) else: # 此时显示所有子计划需要输出的物料 o_objs = SubProductionProgress.objects.filter( subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) ret_0['output'] = list(o_objs.values('subproduction_plan', 'material', 'material__name', 'material__number')) for i in ret_0['output']: i['count_output']=0 ret['forms'] = [] ret_0['id'] = 0 ret_0['name'] = '基本信息' # 查询工具工装 ret_0['tools'] = SubprodctionMaterialListSerializer(instance= SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL, subproduction__subplan_subprod__in = splans), many=True).data # 查询技术文档 ret_0['techdocs'] = TechDocListSerializer(instance = TechDoc.objects.filter(subproduction__subplan_subprod__in = splans, enabled=True)\ .distinct(), many=True).data ret['forms'].append(ret_0) forms = RecordForm.objects.filter(step=vdata['step'], type=RecordForm.RF_TYPE_DO) if forms.exists(): ret['forms'].extend(RecordFormDetailSerializer(instance=forms, many=True).data) return Response(ret) class DoFormSubmit(CreateAPIView, GenericAPIView): perms_map={'*':'*'} serializer_class = OperationSubmitSerializer @transaction.atomic def post(self, request, format=None): """ 提交操作表单 """ data = request.data serializer = OperationSubmitSerializer(data=data, context={'request':self.request}) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data #校验之后的数据 # 创建一个生产操作记录 action_obj = Operation() action_obj.step = vdata['step'] action_obj.remark = vdata.get('remark', '') # 操作备注 action_obj.create_by = request.user action_obj.use_scrap = vdata.get('use_scrap', False) action_obj.save() # 保存关联半成品 if 'wproducts' in data and data['wproducts']: owps = [] for i in data['wproducts']: owp = {} owp['operation'] = action_obj wp = WProduct.objects.get(pk=i) owp['wproduct'] = wp owp['number'] = wp.number owp['material'] = wp.material owp['subproduction_plan'] = wp.subproduction_plan owp['production_plan'] = wp.production_plan owps.append(OperationWproduct(**owp)) OperationWproduct.objects.bulk_create(owps) # 保存物料消耗 for i in vdata['input']: if i['count_input']: #如果有消耗 i_wmat = i['id'] OperationMaterial.objects.create(type=1, operation=action_obj, wmaterial= i_wmat, count=i['count_input']) # 更新车间物料 i_wmat.count = i_wmat.count- i['count_input'] i_wmat.save() # 更新子计划物料消耗情况 sp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan, material=i_wmat.material) sp.count_real = sp.count_real + i['count_input'] sp.save() # 物料产出 if 'output' in data and data['output']: for i in vdata['output']: # 已经序列化好的数据 ma = i['material'] if i['subproduction_plan'].main_product == ma: # 如果是该计划主产物 # 如果是切割 # 获取下一步子工序 if vdata['step'].type == Step.STEP_TYPE_DIV: newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) wpr = dict(material=ma, step=newstep, act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='', subproduction_plan=i['subproduction_plan'], production_plan=i['subproduction_plan'].production_plan) for x in range(i['count_output']): WProduct.objects.create(**wpr) else: # 更新操作产出物料表 OperationMaterial.objects.create(type=2, operation=action_obj, material= ma, count=i['count_output']) # 更新车间物料表 ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i['subproduction_plan'], material=ma) ins.count = ins.count + i['count_output'] ins.save() # 更新子计划进度表 sp = SubProductionProgress.objects.get(subproduction_plan=i['subproduction_plan'], material=ma) sp.count_real = sp.count_real + i['count_input'] sp.save() # 更新动态产品表 if 'wproducts' in vdata and vdata['wproducts']: if vdata['step'].type == Step.STEP_TYPE_COMB: wproducts = vdata['wproducts'] if 'suproduction_plan' in vdata: wproducts.update(is_hidden=True) # 隐藏 newstep, hasNext = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) wproduct = WProduct() wproduct.material = vdata['subproduction_plan'].main_product wproduct.step = newstep wproduct.subproduction_plan=vdata['subproduction_plan'] wproduct.production_plan=vdata['subproduction_plan'].production_plan wproduct.parent = data['wproducts'] if hasNext: wproduct.act_state=WProduct.WPR_ACT_STATE_DOING wproduct.is_executed=False else: wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST wproduct.is_executed=True wproduct.save() else: raise exceptions.APIException('请指定子计划') else: for wproduct in vdata['wproducts']: # 获取下一步子工序 newstep, hasNext = WpmServies.get_next_step(wproduct.subproduction_plan, vdata['step']) wproduct.step = newstep wproduct.pre_step=vdata['step'] if hasNext: wproduct.is_executed= False else: wproduct.is_executed= True wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST wproduct.material=wproduct.subproduction_plan.main_product wproduct.save() # 保存自定义表单结果 for i in vdata['forms']: wr = OperationRecord() wr.form = i['form'] wr.create_by = request.user wr.operation = action_obj wr.save() wrds = [] for m in i['record_data']: # 保存记录详情 form_field = m['form_field'] m['field_name'] = form_field.field_name m['field_key'] = form_field.field_key m['field_type'] = form_field.field_type m['field_value'] = m['field_value'] m['sort'] = form_field.sort m['operation_record'] = wr wrds.append(OperationRecordItem(**m)) OperationRecordItem.objects.bulk_create(wrds) return Response()