hberp/hb_server/apps/wpm/services.py

224 lines
10 KiB
Python

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
from rest_framework.exceptions import ParseError
class WpmService(object):
@classmethod
def get_next_step(cls, subproduction_plan:SubProductionPlan, nowstep:Step):
"""
获取下一步骤
"""
steps_list = subproduction_plan.steps
stepIds = [i['id'] for i in steps_list]
pindex = stepIds.index(nowstep.id)
need_test = steps_list[pindex].get('need_test', False)
if pindex + 1 < len(stepIds):
return Step.objects.get(pk=stepIds[pindex+1]), need_test
else:
return nowstep, need_test
@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
test_i = None
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.subproduction_plan.subproduction.need_combtest : # 配置中需要质检
wproduct.act_state = WProduct.WPR_ACT_STATE_TOCOMBTEST
elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and \
test.is_midtesting is True:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT
test_i = test
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: # 产生半成品编号
if test.number:
wproduct.number = test.number
else:
raise ParseError('请提供玻璃编号')
# 去除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 = ticket.ticket_data
ticket_data['retest_result'] = 1
ticket.ticket_data = ticket_data
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 = test_i
wproduct.last_test_result = is_testok
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]).exclude(step__process__id=1)
| objs.filter(act_state__in=[WProduct.WPR_ACT_STATE_NOTOK, WProduct.WPR_ACT_STATE_SCRAP],
step__process__id=1).exclude(number=None)
).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, is_mtestok=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 add_wproducts_flow_log(cls, instances, change_str=''):
"""
批量创建产品变动日志
"""
WproductFlow.objects.filter(wproduct__in=instances).update(is_lastlog=False)
wfw = []
for i in instances:
ins = WproductFlow()
ins.wproduct = i
for f in WproductFlow._meta.fields:
if f.name not in ['id', 'wproduct', 'is_lastlog']:
setattr(ins, f.name, getattr(i, f.name, None))
ins.change_str = change_str
wfw.append(ins)
WproductFlow.objects.bulk_create(wfw)
@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 outputs:
if i.use_scrap: # 如果使用了边角料
i.count_cut = 0
i.from_material = SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN,
subproduction__subplan_subprod=i.subproduction_plan).first().material
else:
input_q = inputs.filter(subproduction_plan=i.subproduction_plan) # 同计划的消耗
i.from_material = input_q.first().material
count_cut = 0
from_batch = ''
for m in input_q:
count_cut = count_cut + m.count
if from_batch and m.batch:
from_batch = from_batch + ';' + m.batch
else:
from_batch = m.batch
i.count_cut = count_cut
i.from_batch = from_batch
wpfs = WproductFlow.objects.filter(subproduction_plan=i.subproduction_plan,
is_lastlog=True, coperation=op)# 筛选本次操作下子计划的产品日志
i.count_real = wpfs.count()
i.count_ok = wpfs.filter(scrap_reason=None).count()
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()