fix: mlogb质检
This commit is contained in:
parent
95b98df8cf
commit
8eddeb4f70
|
@ -0,0 +1,43 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-01-08 02:16
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('qm', '0033_alter_ftest_test_numer'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='ftest',
|
||||||
|
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='ftestitem',
|
||||||
|
name='test_user',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='操作人'),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='FtestDefect',
|
||||||
|
fields=[
|
||||||
|
('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('has', models.BooleanField(default=False, verbose_name='是否发现')),
|
||||||
|
('defect', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.defect', verbose_name='缺陷')),
|
||||||
|
('ftest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.ftest', verbose_name='关联检验')),
|
||||||
|
('test_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='操作人')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -240,6 +240,7 @@ class Ftest(CommonBDModel):
|
||||||
"""
|
"""
|
||||||
type = models.CharField('检验类型', max_length=20, choices=FTEST_TYPE_CHOICES)
|
type = models.CharField('检验类型', max_length=20, choices=FTEST_TYPE_CHOICES)
|
||||||
test_date = models.DateField('检验日期')
|
test_date = models.DateField('检验日期')
|
||||||
|
qct = models.ForeignKey(Qct, verbose_name='所用质检表', on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
test_numer = models.TextField('检测编号', default='')
|
test_numer = models.TextField('检测编号', default='')
|
||||||
test_group = models.CharField(
|
test_group = models.CharField(
|
||||||
'检验工序集', max_length=20, default='', blank=True)
|
'检验工序集', max_length=20, default='', blank=True)
|
||||||
|
@ -256,6 +257,10 @@ class Ftest(CommonBDModel):
|
||||||
def ftestitems(self):
|
def ftestitems(self):
|
||||||
return FtestItem.objects.filter(ftest=self)
|
return FtestItem.objects.filter(ftest=self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ftestdefects(self):
|
||||||
|
return FtestDefect.objects.filter(ftest=self)
|
||||||
|
|
||||||
|
|
||||||
class FtestItem(BaseModel):
|
class FtestItem(BaseModel):
|
||||||
"""
|
"""
|
||||||
|
@ -265,12 +270,24 @@ class FtestItem(BaseModel):
|
||||||
Ftest, verbose_name='关联检验', on_delete=models.CASCADE)
|
Ftest, verbose_name='关联检验', on_delete=models.CASCADE)
|
||||||
testitem = models.ForeignKey(
|
testitem = models.ForeignKey(
|
||||||
TestItem, verbose_name='质检项目', on_delete=models.CASCADE)
|
TestItem, verbose_name='质检项目', on_delete=models.CASCADE)
|
||||||
|
test_user = models.ForeignKey(User, verbose_name='操作人', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
test_val = models.FloatField('测量值', null=True, blank=True)
|
test_val = models.FloatField('测量值', null=True, blank=True)
|
||||||
check_val = models.FloatField('专检测量值', null=True, blank=True)
|
check_val = models.FloatField('专检测量值', null=True, blank=True)
|
||||||
test_val_json = models.JSONField('测量值', null=True, blank=True)
|
test_val_json = models.JSONField('测量值', null=True, blank=True)
|
||||||
check_val_json = models.JSONField('专检测量值', null=True, blank=True)
|
check_val_json = models.JSONField('专检测量值', null=True, blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
class FtestDefect(BaseModel):
|
||||||
|
"""
|
||||||
|
缺陷明细
|
||||||
|
"""
|
||||||
|
ftest = models.ForeignKey(
|
||||||
|
Ftest, verbose_name='关联检验', on_delete=models.CASCADE)
|
||||||
|
test_user = models.ForeignKey(User, verbose_name='操作人', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
defect = models.ForeignKey(Defect, verbose_name='缺陷', on_delete=models.CASCADE)
|
||||||
|
has = models.BooleanField('是否发现', default=False)
|
||||||
|
|
||||||
|
|
||||||
class Ptest(CommonAModel):
|
class Ptest(CommonAModel):
|
||||||
"""
|
"""
|
||||||
性能测试记录
|
性能测试记录
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from apps.qm.models import (QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest,
|
from apps.qm.models import (QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest,
|
||||||
NotOkOption, Defect, Qct, QctTestItem, QctMat, QctDefect)
|
NotOkOption, Defect, Qct, QctTestItem, QctMat,
|
||||||
|
QctDefect, FtestDefect, FTEST_TYPE_CHOICES)
|
||||||
from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE
|
from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE
|
||||||
from apps.utils.serializers import CustomModelSerializer
|
from apps.utils.serializers import CustomModelSerializer
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
@ -241,3 +242,80 @@ class PtestSerializer(CustomModelSerializer):
|
||||||
if Ptest.objects.filter(sample_number=validated_data['sample_number']).exists():
|
if Ptest.objects.filter(sample_number=validated_data['sample_number']).exists():
|
||||||
raise serializers.ValidationError('该样品编号已存在')
|
raise serializers.ValidationError('该样品编号已存在')
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
|
|
||||||
|
class FtestDefectSerializer(CustomModelSerializer):
|
||||||
|
defect_name = serializers.CharField(source='defect.name', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = FtestDefect
|
||||||
|
fields = '__all__'
|
||||||
|
read_only_fields = EXCLUDE_FIELDS_BASE + ['ftest']
|
||||||
|
|
||||||
|
|
||||||
|
class FtestItemProcessSerializer(CustomModelSerializer):
|
||||||
|
testitem_name = serializers.CharField(
|
||||||
|
source='testitem.name', read_only=True)
|
||||||
|
testitem_description = serializers.CharField(
|
||||||
|
source='testitem.description', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = FtestItem
|
||||||
|
fields = ["id", "testitem", "test_user", "test_val_json", "testitem_name", "testitem_description"]
|
||||||
|
|
||||||
|
class FtestProcessSerializer(CustomModelSerializer):
|
||||||
|
test_user_name = serializers.CharField(
|
||||||
|
source='test_user.name', read_only=True)
|
||||||
|
ftestitems = FtestItemProcessSerializer(label='检验明细', many=True)
|
||||||
|
ftestdefects = FtestDefectSerializer(label='缺陷明细', many=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Ftest
|
||||||
|
fields = ["id", "test_date",
|
||||||
|
"test_user", "note", "ftestitems", "ftestdefects", "qct", "test_user_name"]
|
||||||
|
extra_kwargs = {"qct": {"required": True}}
|
||||||
|
|
||||||
|
def validate(self, attrs):
|
||||||
|
attrs["type"] = "process"
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
def create(self, validated_data):
|
||||||
|
ftestitems = validated_data.pop('ftestitems', [])
|
||||||
|
ftestdefects = validated_data.pop('ftestdefects', [])
|
||||||
|
with transaction.atomic():
|
||||||
|
instance = super().create(validated_data)
|
||||||
|
for item in ftestitems:
|
||||||
|
FtestItem.objects.create(ftest=instance, **item)
|
||||||
|
is_ok = True
|
||||||
|
for item2 in ftestdefects:
|
||||||
|
defect:Defect = item["defect"]
|
||||||
|
if defect.okcate in [Defect.DEFECT_NOTOK] and item["has"]:
|
||||||
|
is_ok = False
|
||||||
|
FtestDefect.objects.create(ftest=instance, **item2)
|
||||||
|
instance.is_ok = is_ok
|
||||||
|
instance.save()
|
||||||
|
return instance
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
ftestitems = validated_data.pop('ftestitems', [])
|
||||||
|
ftestdefects = validated_data.pop('ftestdefects', [])
|
||||||
|
with transaction.atomic():
|
||||||
|
instance = super().update(instance, validated_data)
|
||||||
|
for item in ftestitems:
|
||||||
|
if "id" in item and item["id"]:
|
||||||
|
FtestItem.objects.filter(id=item["id"]).update(
|
||||||
|
test_user = item["test_user"],
|
||||||
|
test_val_json = item["test_val_json"])
|
||||||
|
else:
|
||||||
|
FtestItem.objects.create(ftest=instance, **item)
|
||||||
|
is_ok = True
|
||||||
|
for item2 in ftestdefects:
|
||||||
|
if "id" in item2 and item2["id"]:
|
||||||
|
ins: FtestDefect = FtestDefect.objects.get(id=item2["id"])
|
||||||
|
else:
|
||||||
|
ins = FtestDefect.objects.create(ftest=instance, **item2)
|
||||||
|
ins.has = item2["has"]
|
||||||
|
ins.save()
|
||||||
|
if ins.has and ins.defect.okcate in [Defect.DEFECT_NOTOK]:
|
||||||
|
is_ok = False
|
||||||
|
instance.is_ok = is_ok
|
||||||
|
instance.save()
|
||||||
|
return instance
|
|
@ -0,0 +1,20 @@
|
||||||
|
# Generated by Django 3.2.12 on 2025-01-08 02:16
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('qm', '0034_auto_20250108_1016'),
|
||||||
|
('wpm', '0082_mlogb_qct'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='mlogbw',
|
||||||
|
name='ftest',
|
||||||
|
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='qm.ftest', verbose_name='关联检验'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -354,6 +354,7 @@ class Mlogbw(BaseModel):
|
||||||
mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE)
|
mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE)
|
||||||
wpr = models.ForeignKey("wpmw.wpr", verbose_name='关联产品', on_delete=models.SET_NULL
|
wpr = models.ForeignKey("wpmw.wpr", verbose_name='关联产品', on_delete=models.SET_NULL
|
||||||
, related_name='wpr_mlogbw', null=True, blank=True)
|
, related_name='wpr_mlogbw', null=True, blank=True)
|
||||||
|
ftest = models.OneToOneField("qm.ftest", verbose_name='关联检验', on_delete=models.PROTECT, null=True, blank=True)
|
||||||
note = models.TextField('备注', null=True, blank=True)
|
note = models.TextField('备注', null=True, blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ from django.utils.timezone import localdate
|
||||||
from apps.qm.models import NotOkOption
|
from apps.qm.models import NotOkOption
|
||||||
from apps.wf.serializers import TicketSimpleSerializer
|
from apps.wf.serializers import TicketSimpleSerializer
|
||||||
from apps.wpmw.models import Wpr
|
from apps.wpmw.models import Wpr
|
||||||
|
from apps.qm.serializers import FtestProcessSerializer
|
||||||
import logging
|
import logging
|
||||||
mylogger = logging.getLogger("log")
|
mylogger = logging.getLogger("log")
|
||||||
|
|
||||||
|
@ -572,9 +573,10 @@ class MlogbInUpdateSerializer(CustomModelSerializer):
|
||||||
fields = ['id', 'count_use', 'count_break', 'count_pn_jgqbl', 'note']
|
fields = ['id', 'count_use', 'count_break', 'count_pn_jgqbl', 'note']
|
||||||
|
|
||||||
class MlogbwCreateUpdateSerializer(CustomModelSerializer):
|
class MlogbwCreateUpdateSerializer(CustomModelSerializer):
|
||||||
|
ftest = FtestProcessSerializer(required=False)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Mlogbw
|
model = Mlogbw
|
||||||
fields = ["id", "number", "wpr", "note", "mlogb"]
|
fields = ["id", "number", "wpr", "note", "mlogb", "ftest"]
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
mlogb:Mlogb = attrs["mlogb"]
|
mlogb:Mlogb = attrs["mlogb"]
|
||||||
|
@ -588,8 +590,7 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer):
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance, validated_data):
|
||||||
validated_data.pop("mlogb")
|
validated_data.pop("mlogb")
|
||||||
return super().update(instance, validated_data)
|
super().update(instance, validated_data)
|
||||||
|
|
||||||
|
|
||||||
class MlogbOutUpdateSerializer(CustomModelSerializer):
|
class MlogbOutUpdateSerializer(CustomModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -521,8 +521,10 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
|
||||||
d_count_ok = xcount
|
d_count_ok = xcount
|
||||||
# 找寻质检表
|
# 找寻质检表
|
||||||
qctmat = QctMat.objects.filter(material=material_out).order_by("-create_time").first()
|
qctmat = QctMat.objects.filter(material=material_out).order_by("-create_time").first()
|
||||||
|
qct = None
|
||||||
if qctmat:
|
if qctmat:
|
||||||
mlogbout.qct = qctmat.qct
|
qct = qctmat.qct
|
||||||
|
mlogbout.qct = qct
|
||||||
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()
|
||||||
|
@ -614,11 +616,13 @@ class MlogbwViewSet(CustomModelViewSet):
|
||||||
self.cal_mlogb_count(mlogb_to)
|
self.cal_mlogb_count(mlogb_to)
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def perform_destroy(self, instance):
|
def perform_destroy(self, instance:Mlogbw):
|
||||||
mlogb = instance.mlogb
|
mlogb = instance.mlogb
|
||||||
if mlogb.mlog.submit_time is not None:
|
if mlogb.mlog.submit_time is not None:
|
||||||
raise ParseError('日志已提交不可修改')
|
raise ParseError('日志已提交不可修改')
|
||||||
instance.delete()
|
instance.delete()
|
||||||
|
if instance.ftest:
|
||||||
|
instance.ftest.delete()
|
||||||
self.cal_mlogb_count(mlogb)
|
self.cal_mlogb_count(mlogb)
|
||||||
# 如果是输入且输出追踪到个,需同步创建
|
# 如果是输入且输出追踪到个,需同步创建
|
||||||
material_in: Material = mlogb.material_in
|
material_in: Material = mlogb.material_in
|
||||||
|
|
Loading…
Reference in New Issue