feat: 批次处理做兼容性处理

This commit is contained in:
caoqianming 2025-02-28 15:31:38 +08:00
parent 77f7a454a1
commit 286a5306e3
5 changed files with 89 additions and 73 deletions

View File

@ -151,7 +151,7 @@ QC_TRACE_CHOICES = (
class Qct(CommonAModel): class Qct(CommonAModel):
name = models.CharField(max_length=50, verbose_name="名称") name = models.CharField(max_length=50, verbose_name="名称")
number = models.CharField(max_length=20, verbose_name="编号") number = models.CharField(max_length=20, verbose_name="编号")
tags = models.JSONField('检测类型', default=list, blank=True) tags = models.JSONField('检测类型', default=list, blank=True) # process 和 inm
testitems = models.ManyToManyField(TestItem, verbose_name="检测项", blank=True, through='qm.qcttestitem') testitems = models.ManyToManyField(TestItem, verbose_name="检测项", blank=True, through='qm.qcttestitem')
defects = models.ManyToManyField(Defect, verbose_name="缺陷项", blank=True, through='qm.qctdefect') defects = models.ManyToManyField(Defect, verbose_name="缺陷项", blank=True, through='qm.qctdefect')
materials = models.ManyToManyField(Material, verbose_name="物料", blank=True, through='qm.qctmat') materials = models.ManyToManyField(Material, verbose_name="物料", blank=True, through='qm.qctmat')

View File

@ -382,6 +382,26 @@ class Mlogbw(BaseModel):
on_delete=models.PROTECT, null=True, blank=True, related_name="mlogbw_ftest") on_delete=models.PROTECT, null=True, blank=True, related_name="mlogbw_ftest")
note = models.TextField('备注', null=True, blank=True) note = models.TextField('备注', null=True, blank=True)
@classmethod
def cal_count_notok(mlogb: Mlog):
count = Mlogbw.objects.filter(mlogb=mlogb).count()
if mlogb.material_in:
mlogb.count_use = count
elif mlogb.material_out:
mlogb.count_real = count
count_notok = 0
tqs = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).values("defect_main").annotate(xcount=Count('id'))
md_ids = []
for t in tqs:
md, _ = MlogbDefect.objects.get_or_create(mlogb=mlogb, defect=t["defect_main"])
md.count = t["xcount"]
md.save()
md_ids.append(md.id)
count_notok += t["xcount"]
MlogbDefect.objects.filter(mlogb=mlogb).exclude(id__in=md_ids).delete()
mlogb.count_notok = count_notok
mlogb.count_ok = count - mlogb.count_notok
mlogb.save()
class Handover(CommonADModel): class Handover(CommonADModel):
""" """

View File

@ -724,7 +724,7 @@ class MlogbOutUpdateSerializer(CustomModelSerializer):
return ins return ins
def update(self, instance, validated_data): def update(self, instance, validated_data):
material_out:Material = validated_data["material_out"] material_out:Material = instance.material_out
mlogbdefect = validated_data.pop("mlogbdefect", []) mlogbdefect = validated_data.pop("mlogbdefect", [])
with transaction.atomic(): with transaction.atomic():
ins:Mlogb = super().update(instance, validated_data) ins:Mlogb = super().update(instance, validated_data)

View File

@ -11,7 +11,7 @@ from apps.system.models import User
from apps.pm.models import Mtask from apps.pm.models import Mtask
from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack, Team, Srule from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack, Team, Srule
from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw from .models import SfLog, WMaterial, Mlog, Mlogb, Mlogbw, Handover, Handoverb, Handoverbw, MlogbDefect
from apps.mtm.services_2 import cal_material_count from apps.mtm.services_2 import cal_material_count
from apps.wf.models import Ticket from apps.wf.models import Ticket
from apps.utils.thread import MyThread from apps.utils.thread import MyThread
@ -233,29 +233,35 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
process = mgroup.process process = mgroup.process
into_wm_mgroup = process.into_wm_mgroup into_wm_mgroup = process.into_wm_mgroup
need_store_notok = process.store_notok need_store_notok = process.store_notok
m_outs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
stored_notok = need_store_notok stored_notok = need_store_notok
stored_mgroup = need_store_notok stored_mgroup = need_store_notok
if m_outs.exists(): if mlogb_out_qs.exists():
m_outs_list = [(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight, None, mo) for mo in m_outs.all()] m_outs_list = [(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight, None, mo) for mo in mlogb_out_qs.all()]
if need_store_notok: if need_store_notok:
for item in m_outs: for item in mlogb_out_qs:
if item.material_out.tracking == Material.MA_TRACKING_SINGLE: if item.qct is not None:
# 获取所有主要的不合格项 if MlogbDefect.objects.filter(mlogb=item).exists():
bw_qs = Mlogbw.objects.filter(mlogb=item) pass
defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct() else:
defects_map = {d.id: d for d in Defect.objects.filter(id__in=defectIds)} Mlogbw.cal_count_notok(item)
# 过滤并统计相关数据 for itemx in MlogbDefect.objects.filter(mlogb=item):
filtered_bw_qs = bw_qs.filter( m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item))
ftest__defect_main__id__in=defects_map.keys() # # 获取所有主要的不合格项/先暂时保留
).values('ftest__defect_main__id').annotate(xcount=Count('id')) # bw_qs = Mlogbw.objects.filter(mlogb=item)
# 整理结果 # defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct()
for defect_data in filtered_bw_qs: # defects_map = {d.id: d for d in Defect.objects.filter(id__in=defectIds)}
defect_id = defect_data['ftest__defect_main__id'] # # 过滤并统计相关数据
xcount = defect_data['xcount'] # filtered_bw_qs = bw_qs.filter(
if xcount > 0: # ftest__defect_main__id__in=defects_map.keys()
defect = defects_map[defect_id] # ).values('ftest__defect_main__id').annotate(xcount=Count('id'))
m_outs_list.append((item.material_out, item.batch, xcount, 0, defect, item)) # # 整理结果
# for defect_data in filtered_bw_qs:
# defect_id = defect_data['ftest__defect_main__id']
# xcount = defect_data['xcount']
# if xcount > 0:
# defect = defects_map[defect_id]
# m_outs_list.append((item.material_out, item.batch, xcount, 0, defect, item))
else: else:
for f in Mlogb._meta.fields: for f in Mlogb._meta.fields:
if 'count_n_' in f.name and getattr(item, f.name) > 0: if 'count_n_' in f.name and getattr(item, f.name) > 0:
@ -358,29 +364,36 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
if material_out or is_fix: # 产物退回 if material_out or is_fix: # 产物退回
# 有多个产物的情况 # 有多个产物的情况
# 需要考虑不合格品退回的情况 # 需要考虑不合格品退回的情况
m_outs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False)
if m_outs.exists(): if mlogb_out_qs.exists():
m_outs_list = [ m_outs_list = [
(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight, None, mo) (mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight, None, mo)
for mo in m_outs.all()] for mo in mlogb_out_qs.all()]
if stored_notok: if stored_notok:
for item in m_outs: for item in mlogb_out_qs:
if item.material_out.tracking == Material.MA_TRACKING_SINGLE: if item.qct is not None:
# 获取所有主要的不合格项 if MlogbDefect.objects.filter(mlogb=item).exists():
bw_qs = Mlogbw.objects.filter(mlogb=item) pass
defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct() else:
defects_map = {d.id: d for d in Defect.objects.filter(id__in=defectIds)} Mlogbw.cal_count_notok(item)
# 过滤并统计相关数据 for itemx in MlogbDefect.objects.filter(mlogb=item):
filtered_bw_qs = bw_qs.filter( m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item))
ftest__defect_main__id__in=defects_map.keys() # if item.material_out.tracking == Material.MA_TRACKING_SINGLE:
).values('ftest__defect_main__id').annotate(xcount=Count('id')) # # 获取所有主要的不合格项
# 整理结果 # bw_qs = Mlogbw.objects.filter(mlogb=item)
for defect_data in filtered_bw_qs: # defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct()
defect_id = defect_data['ftest__defect_main__id'] # defects_map = {d.id: d for d in Defect.objects.filter(id__in=defectIds)}
xcount = defect_data['xcount'] # # 过滤并统计相关数据
if xcount > 0: # filtered_bw_qs = bw_qs.filter(
defect = defects_map[defect_id] # ftest__defect_main__id__in=defects_map.keys()
m_outs_list.append((item.material_out, item.batch, xcount, 0, defect, item)) # ).values('ftest__defect_main__id').annotate(xcount=Count('id'))
# # 整理结果
# for defect_data in filtered_bw_qs:
# defect_id = defect_data['ftest__defect_main__id']
# xcount = defect_data['xcount']
# if xcount > 0:
# defect = defects_map[defect_id]
# m_outs_list.append((item.material_out, item.batch, xcount, 0, defect, item))
else: else:
for f in Mlogb._meta.fields: for f in Mlogb._meta.fields:
if 'count_n_' in f.name and getattr(item, f.name) > 0: if 'count_n_' in f.name and getattr(item, f.name) > 0:

View File

@ -592,13 +592,17 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
d_count_real = mlogbin.count_use d_count_real = mlogbin.count_use
d_count_ok = mlogbin.count_use d_count_ok = mlogbin.count_use
# 找寻质检表 # 找寻质检表
if material_out.tracking == Material.MA_TRACKING_SINGLE: if is_fix and mgroup.process.type == Process.PRO_PROD:
if is_fix and mgroup.process.type == Process.PRO_PROD: # 如果是生产返修,则忽略质检
# 如果是生产返修,则忽略质检 pass
pass elif mlogbout.qct:
else: try:
qctmat = QctMat.objects.filter(material=material_out, qct__is_deleted=False).order_by("-create_time").first() qctmat = QctMat.objects.get(material=material_out, qct__is_deleted=False, qct__tags__contains="process").order_by("-create_time")
mlogbout.qct = qctmat.qct if qctmat else None except QctMat.DoesNotExist:
qctmat = None
except QctMat.MultipleObjectsReturned:
raise ParseError("存在多个质检表,请手动选择")
mlogbout.qct = qctmat.qct if qctmat else None
mlogbout.count_real = d_count_real mlogbout.count_real = d_count_real
mlogbout.count_ok = d_count_ok mlogbout.count_ok = d_count_ok
mlogbout.save() mlogbout.save()
@ -672,27 +676,6 @@ class MlogbwViewSet(CustomModelViewSet):
raise ParseError('请指定所属消耗/产出明细') raise ParseError('请指定所属消耗/产出明细')
return super().filter_queryset(queryset) return super().filter_queryset(queryset)
def cal_mlogb_count(self, mlogb):
count = Mlogbw.objects.filter(mlogb=mlogb).count()
# 此处先不管检验问题
if mlogb.material_in:
mlogb.count_use = count
elif mlogb.material_out:
mlogb.count_real = count
count_notok = 0
tqs = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).values("defect_main").annotate(xcount=Count('id'))
md_ids = []
for t in tqs:
md, _ = MlogbDefect.objects.get_or_create(mlogb=mlogb, defect=t["defect_main"])
md.count = t["xcount"]
md.save()
md_ids.append(md.id)
count_notok += t["xcount"]
MlogbDefect.objects.filter(mlogb=mlogb).exclude(id__in=md_ids).delete()
mlogb.count_notok = count_notok
mlogb.count_ok = count - mlogb.count_notok
mlogb.save()
@transaction.atomic @transaction.atomic
def perform_create(self, serializer): def perform_create(self, serializer):
ins:Mlogbw = serializer.save() ins:Mlogbw = serializer.save()
@ -715,7 +698,7 @@ class MlogbwViewSet(CustomModelViewSet):
@transaction.atomic @transaction.atomic
def perform_update(self, serializer): def perform_update(self, serializer):
mlogbw = serializer.save() mlogbw = serializer.save()
self.cal_mlogb_count(mlogbw.mlogb) Mlogbw.cal_count_notok(mlogbw.mlogb)
@transaction.atomic @transaction.atomic
def perform_destroy(self, instance:Mlogbw): def perform_destroy(self, instance:Mlogbw):
@ -736,4 +719,4 @@ class MlogbwViewSet(CustomModelViewSet):
mbws = Mlogbw.objects.filter(Q(wpr=instance.wpr)|Q(number__contains=instance.number), mlogb=mlogb_to) mbws = Mlogbw.objects.filter(Q(wpr=instance.wpr)|Q(number__contains=instance.number), mlogb=mlogb_to)
Ftest.objects.filter(id__in=mbws.values_list('ftest__id', flat=True)).delete() Ftest.objects.filter(id__in=mbws.values_list('ftest__id', flat=True)).delete()
mbws.delete() mbws.delete()
self.cal_mlogb_count(mlogb_to) Mlogbw.cal_count_notok(mlogb)