220 lines
9.9 KiB
Python
220 lines
9.9 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
|
|
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: # 产生半成品编号
|
|
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 = 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() |