from django.utils import timezone from typing import List from django.db.models.expressions import F from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress from apps.mtm.models import Material, Step, SubprodctionMaterial from apps.qm.models import TestRecord from apps.system.models import User from apps.wf.models import State, TicketFlow, Transition from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow, WprouctTicket from utils.tools import ranstr class WpmServies(object): @classmethod def get_next_step(cls, subproduction_plan:SubProductionPlan, nowstep:Step): """ 获取下一步骤 """ stepIds = [i['id'] for i in subproduction_plan.steps] pindex = stepIds.index(nowstep.id) if pindex + 1 < len(stepIds): return Step.objects.get(pk=stepIds[pindex+1]), True else: return nowstep, False @classmethod def get_subplans_queryset_from_wproducts(cls, wproducts:List): """ 通过半成品列表获取所属子计划 """ splans = SubProductionPlan.objects.filter(is_deleted=False, wproduct_subplan__in=wproducts) return splans @classmethod def get_subplans_queyset_from_step(cls, step:Step): """ 通过当前操作获取所有正在进行的子计划 """ splans = SubProductionPlan.objects.filter(is_deleted=False, subproduction__usedstep_subproduction__step=step, state=SubProductionPlan.SUBPLAN_STATE_WORKING) return splans @classmethod def update_wproduct_by_test(cls, test:TestRecord, user:User): """ 根据检验结果更新玻璃及相关状态 """ is_testok = test.is_testok wproduct = test.wproduct if is_testok: if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检 wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD: # 成品检验 wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST else: wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.number is None: # 产生半成品编号 wproduct.number = 'WP'+ranstr(7) # 去除ng_sign if wproduct.ng_sign: wt = WprouctTicket.objects.order_by('id').last() #取最后的工单 if wt.step.process == test.step.process: wproduct.ng_sign = None ticket = wt.ticket ticket_data = wt.ticket_data ticket_data['retest_result'] = 1 ticket.update_by = user ticket.save() # 创建处理日志 TicketFlow.objects.create(ticket=ticket, state=ticket.state, participant_type=State.PARTICIPANT_TYPE_PERSONAL, intervene_type=0, participant=user) else:# 如果不合格 wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK # 需要走不合格品审理的工单 # 如果已经是返工返修的产品 if wproduct.ng_sign: wt = WprouctTicket.objects.order_by('id').last() #取最后的工单 if wt.step.process == test.step.process: ticket = wt.ticket ticket_data = wt.ticket_data ticket_data['retest_result'] = 0 ticket.update_by = user ticket.save() # 创建处理日志 TicketFlow.objects.create(ticket=ticket, state=ticket.state, participant_type=State.PARTICIPANT_TYPE_PERSONAL, intervene_type=0, participant=user) wproduct.update_by = user wproduct.update_time = timezone.now() wproduct.test = None wproduct.save() # 添加日志 cls.add_wproduct_flow_log(wproduct, 'test_ok' if is_testok else 'test_notok') # 更新子计划相关进度 cls.update_subproduction_progress_main(sp=wproduct.subproduction_plan) @classmethod def update_subproduction_progress_main(cls, sp:SubProductionPlan): """ 根据产品变动日志更新生产进度 """ objs = WproductFlow.objects.filter(subproduction_plan=sp, is_lastlog=True) count_ok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_INM, WProduct.WPR_ACT_STATE_OK, WProduct.WPR_ACT_STATE_SELLED]).count() count_notok = objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP]).count() count_real = objs.exclude(act_state__in=[WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_DOWAIT, WProduct.WPR_ACT_STATE_DOING]).count() ins = SubProductionProgress.objects.filter(subproduction_plan=sp, is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT).first() if ins: ins.count_ok = count_ok ins.count_notok = count_notok ins.count_real = count_real ins.save() @classmethod def update_plan_state_by_mtestok(cls, plan:ProductionPlan): """ 根据军检结果更新主计划状态 """ # 计算计划军检合格数并进行状态变更 count_mtestok = WProduct.objects.filter(material=plan.product, iproduct_wproduct__ismtestok=True, is_deleted=False).count() plan.count_mtestok = count_mtestok if count_mtestok >= plan.count: plan.state = ProductionPlan.PLAN_MTEST_DONE plan.save() @classmethod def add_wproduct_flow_log(cls, instance:WProduct, change_str:str=''): """ 创建产品变动日志 """ # update_fields = kwargs['update_fields'] WproductFlow.objects.filter(wproduct=instance, subproduction_plan=instance.subproduction_plan).update(is_lastlog=False) ins = WproductFlow() ins.wproduct = instance for f in WproductFlow._meta.fields: if f.name not in ['id', 'wproduct', 'is_lastlog']: setattr(ins, f.name, getattr(instance, f.name, None)) ins.change_str = change_str ins.save() @classmethod def update_cutting_list_with_operation(cls, op:Operation): """ 根据车间操作更新下料清单 """ inputs = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_IN) outputs = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) for i in inputs: sp = i.subproduction_plan i.count_cut = outputs.filter(subproduction_plan=sp).first().count i.count_real = sp.count_real i.count_ok = sp.count_ok wpfs = WproductFlow.objects.filter(subproduction_plan=sp, is_lastlog=True) i.count_qipao = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_QIPAO).count() i.count_podian = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_PODIAN).count() i.count_hua = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_HUA).count() i.count_other = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_OTHER).count() i.is_cutting = True i.save() @classmethod def update_cutting_list_with_sp(cls, sp:SubProductionPlan): """ 根据子计划更新下料清单 """ wpfs = WproductFlow.objects.filter(subproduction_plan=sp, is_lastlog=True) for i in OperationMaterial.objects.filter(subproduction_plan=sp, is_cutting=True): i.count_real = sp.count_real i.count_ok = sp.count_ok i.count_qipao = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_QIPAO).count() i.count_podian = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_PODIAN).count() i.count_hua = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_HUA).count() i.count_other = wpfs.filter(scrap_reason=WProduct.SCRAP_REASON_OTHER).count() i.save()