feat: mlog填写支持defect定义

This commit is contained in:
caoqianming 2025-03-03 18:21:03 +08:00
parent 5245689ec2
commit 9907bf7c43
5 changed files with 120 additions and 36 deletions

View File

@ -316,6 +316,25 @@ class Ftest(CommonBDModel):
FtestDefect.objects.create(ftest=ftest, defect=defect)
return ftest
# @classmethod
# def cal_count_notok(cls, ftestwork: FtestWork):
# count = Ftest.objects.filter(ftest_work=ftestwork).count()
# mlogb.count_real = count
# count_notok = 0
# tqs = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False)
# tqs_a = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).values("ftest__defect_main").annotate(xcount=Count('id'))
# defects = {defect.id: defect for defect in Defect.objects.filter(id__in=tqs.values_list("ftest__defect_main", flat=True))}
# md_ids = []
# for t in tqs_a:
# md, _ = MlogbDefect.objects.get_or_create(mlogb=mlogb, defect=defects[t["ftest__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 FtestItem(BaseModel):
"""

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.12 on 2025-03-03 09:08
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('qm', '0046_alter_testitem_description'),
('wpm', '0090_mlogbdefect_floor'),
]
operations = [
migrations.AddField(
model_name='mlog',
name='qct',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='qm.qct', verbose_name='所用质检表'),
),
migrations.AddField(
model_name='mlogbdefect',
name='count_test',
field=models.IntegerField(blank=True, null=True, verbose_name='抽检数'),
),
]

View File

@ -172,6 +172,7 @@ class Mlog(CommonADModel):
fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:仅二级;20:二三级;30:一二级')
mtype = models.PositiveSmallIntegerField('生产类型', default=10, help_text='10:自生产;20:外协生产', choices=((10, '自生产'), (20, '外协生产')))
is_fix = models.BooleanField('是否用于返修', default=False)
qct = models.ForeignKey("qm.qct", verbose_name='所用质检表', on_delete=models.SET_NULL, null=True, blank=True)
supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True)
work_start_time = models.DateTimeField('生产开始时间', null=True, blank=True)
work_end_time = models.DateTimeField('生产结束时间', null=True, blank=True)
@ -288,7 +289,17 @@ class Mlog(CommonADModel):
def audit_ignore_fields(self):
return ['create_by', 'update_by',
'create_time', 'update_time', 'id']
@property
def mlogdefect(self):
return MlogbDefect.objects.filter(mlogb__mlog=self)
def cal_count_notok(self):
count_notok = MlogbDefect.objects.filter(defect__okcate=30, mlogb__mlog=self).aggregate(total=Sum("count"))["total"] or 0
self.count_notok = count_notok
self.count_ok = self.count_real - count_notok
self.save(update_fields=["count_ok", "count_notok"])
@classmethod
def count_fields(cls):
mlog_count_fields = []
@ -363,10 +374,16 @@ class Mlogb(BaseModel):
def mlogbdefect(self):
return MlogbDefect.objects.filter(mlogb=self)
def cal_count_notok(self):
count_notok = MlogbDefect.objects.filter(defect__okcate=30, mlogb=self).aggregate(total=Sum("count"))["total"] or 0
self.count_notok = count_notok
self.count_ok = self.count_real - count_notok
self.save(update_fields=["count_ok", "count_notok"])
class MlogbDefect(BaseModel):
mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE)
defect = models.ForeignKey("qm.Defect", verbose_name='缺陷', on_delete=models.CASCADE)
count_test = models.IntegerField("抽检数", null=True, blank=True)
floor = models.IntegerField("层数", null=True, blank=True)
count = models.PositiveIntegerField('数量', default=0)

View File

@ -18,7 +18,7 @@ from django.db import transaction
from django.utils import timezone
from django.core.cache import cache
from django.utils.timezone import localdate
from apps.qm.models import NotOkOption, Ftest
from apps.qm.models import NotOkOption, Qct
from apps.wf.serializers import TicketSimpleSerializer
from apps.wpmw.models import Wpr
from apps.qm.serializers import FtestProcessSerializer
@ -202,12 +202,19 @@ class WMaterialSerializer(CustomModelSerializer):
ret['count_cando'] = ret['count'] - ret['count_working']
return ret
class MlogbDefectSerializer(CustomModelSerializer):
defect_name = serializers.CharField(source="defect.name", read_only=True)
class Meta:
model = MlogbDefect
fields = ["id", "defect_name", "count", "mlogb", "defect", "floor", "count_test"]
read_only_fields = EXCLUDE_FIELDS_BASE + ["mlogb"]
class MlogbSerializer(CustomModelSerializer):
material_out_ = MaterialSimpleSerializer(
source='material_out', read_only=True)
material_out_name = serializers.StringRelatedField(
source='material_out', read_only=True)
mlogbdefect = MlogbDefectSerializer(many=True)
class Meta:
model = Mlogb
@ -261,13 +268,6 @@ class MlogListSerializer(CustomModelSerializer):
model = Mlog
fields = '__all__'
class MlogbDefectSerializer(CustomModelSerializer):
defect_name = serializers.CharField(source="defect.name", read_only=True)
class Meta:
model = MlogbDefect
fields = ["id", "defect_name", "count", "mlogb", "defect", "floor"]
read_only_fields = EXCLUDE_FIELDS_BASE + ["mlogb"]
class MlogbDetailSerializer(CustomModelSerializer):
material_out_name = serializers.StringRelatedField(
@ -324,6 +324,7 @@ class MlogSerializer(CustomModelSerializer):
ticket_ = TicketSimpleSerializer(source='ticket', read_only=True)
test_user_name = serializers.CharField(source='test_user.name', read_only=True)
mlogdefect = MlogbDefectSerializer(many=True)
class Meta:
model = Mlog
fields = '__all__'
@ -338,6 +339,7 @@ class MlogSerializer(CustomModelSerializer):
def create(self, validated_data):
material_out = validated_data['material_out']
mtask:Mtask = validated_data.get('mtask', None)
mlogdefect = validated_data.pop('mlogdefect', [])
if mtask and mtask.state != Mtask.MTASK_ASSGINED:
raise ParseError('该任务非下达中不可选择')
with transaction.atomic():
@ -393,13 +395,25 @@ class MlogSerializer(CustomModelSerializer):
'count_ok': instance.count_ok, 'count_notok': instance.count_notok,
'count_break_t': instance.count_break_t
}
for f in Mlogb._meta.fields:
if 'count_n_' in f.name:
add_dict_2[f.name] = getattr(instance, f.name)
need_mdfect = False
if instance.qct or mlogdefect:
need_mdfect = True
else:
for f in Mlogb._meta.fields:
if 'count_n_' in f.name:
add_dict_2[f.name] = getattr(instance, f.name)
ddict = {}
if wm_in:
ddict = {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom}
Mlogb.objects.get_or_create(**add_dict_2, defaults=ddict)
mlogb, _ = Mlogb.objects.get_or_create(**add_dict_2, defaults=ddict)
if need_mdfect:
mlogb_defect_objects = [
MlogbDefect(**{**item, "mlogb": mlogb})
for item in mlogdefect if item["count"] > 0
]
if mlogb_defect_objects:
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
instance.cal_count_notok()
return instance
def update(self, instance, validated_data):
@ -407,6 +421,7 @@ class MlogSerializer(CustomModelSerializer):
raise ParseError('不支持的填写类型')
validated_data.pop('mtask', None)
validated_data.pop('mgroup', None)
mlogdefect = validated_data.pop('mlogdefect', [])
if instance.mtask:
validated_data.pop('handle_date', None)
# validated_data.pop('handle_user', None)
@ -463,11 +478,24 @@ class MlogSerializer(CustomModelSerializer):
if wm_in:
mox.batch_ofrom = wm_in.batch
mox.material_ofrom = wm_in.material_ofrom
for f in Mlogb._meta.fields:
if 'count_n_' in f.name:
setattr(mox, f.name, getattr(instance, f.name))
need_mdefect=False
if instance.qct or mlogdefect:
need_mdefect = True
else:
for f in Mlogb._meta.fields:
if 'count_n_' in f.name:
setattr(mox, f.name, getattr(instance, f.name))
mox.save()
Mlogb.objects.filter(mlog=instance, material_out__isnull=False).exclude(id=mox.id).delete()
if need_mdefect:
MlogbDefect.objects.filter(mlogb__mlog=instance).delete()
mlogb_defect_objects = [
MlogbDefect(**{**item, "mlogb": mlogb})
for item in mlogdefect if item["count"] > 0
]
if mlogb_defect_objects:
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
instance.cal_count_notok()
return instance
def validate(self, attrs):
@ -576,6 +604,8 @@ class MlogInitSerializer(CustomModelSerializer):
raise ParseError('外协必须选择外协单位')
if attrs.get('work_end_time', None):
attrs['handle_date'] = localdate(attrs['work_end_time'])
if attrs["material_out"]:
attrs["qct"] = Qct.get(attrs["material_out"], "process")
return attrs
class MlogChangeSerializer(CustomModelSerializer):
@ -726,27 +756,20 @@ class MlogbOutUpdateSerializer(CustomModelSerializer):
# else:
# raise ParseError("mlogbdefect仅支持批次件")
# return ins
@transaction.atomic
def update(self, instance, validated_data):
mlogbdefect = validated_data.pop("mlogbdefect", [])
with transaction.atomic():
ins:Mlogb = super().update(instance, validated_data)
if (instance.qct or mlogbdefect) and instance.material_out.tracking == Material.MA_TRACKING_BATCH:
count_notok = 0
md_ids = []
for item in mlogbdefect:
defect:Defect = item["defect"]
if item["count"] > 0:
insb, _ = MlogbDefect.objects.get_or_create(mlogb=ins, defect=defect, floor=item.get('floor', None))
insb.count = item["count"]
insb.save(update_fields=["count"])
if defect.okcate == Defect.DEFECT_NOTOK:
count_notok += item["count"]
md_ids.append(insb.id)
MlogbDefect.objects.filter(mlogb=ins).exclude(id__in=md_ids).delete()
ins.count_notok = count_notok
ins.count_ok = ins.count_real - ins.count_notok
ins.save()
if (ins.qct or mlogbdefect) and ins.material_out.tracking == Material.MA_TRACKING_BATCH:
MlogbDefect.objects.filter(mlogb=ins).delete()
mlogb_defect_objects = [
MlogbDefect(**{**item, "mlogb": ins})
for item in mlogbdefect if item["count"] > 0
]
if mlogb_defect_objects:
MlogbDefect.objects.bulk_create(mlogb_defect_objects)
ins.cal_count_notok()
return ins
def validate(self, attrs):

View File

@ -596,7 +596,7 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
# 如果是生产返修,则忽略质检
pass
elif mlogbout.qct is None:
mlogbout.qct = Qct.get(mlogbout.material_out, "process")
mlogbout.qct = Qct.get(mlogbout.material_out, "process") if mlog.qct is None else mlog.qct
mlogbout.count_real = d_count_real
mlogbout.count_ok = d_count_ok
mlogbout.save()
@ -628,11 +628,11 @@ class MlogbOutViewSet(UpdateModelMixin, CustomGenericViewSet):
serializer_class = MlogbOutUpdateSerializer
class FmlogViewSet(CustomModelViewSet):
class FmlogViewSet(CustomListModelMixin, BulkCreateModelMixin, BulkDestroyModelMixin, CustomGenericViewSet):
perms_map = {'get': '*', 'post': 'mlog.create', 'put': 'mlog.update', 'delete': 'mlog.delete'}
queryset = Fmlog.objects.all()
serializer_class = FmlogSerializer
update_serializer_class = FmlogUpdateSerializer
# update_serializer_class = FmlogUpdateSerializer
filterset_fields = ['mtask', 'mgroup', 'mtask__route']
select_related_fields = ['mtask', 'mgroup', 'mtask__route', 'mtask__route__routepack']