This commit is contained in:
zty 2025-01-09 13:36:58 +08:00
commit 4a3934b4fd
8 changed files with 47 additions and 115 deletions

View File

@ -235,6 +235,20 @@ class FtestWork(CommonBDModel):
ftestwork_count_fields.append(f.name) ftestwork_count_fields.append(f.name)
return ftestwork_count_fields return ftestwork_count_fields
# def cal_count(self):
# self.count_notok = FtestworkDefect.objects.filter(
# mlogb=self, defect__okcate=30).aggregate(total=Sum("count"))["total"] or 0
# self.count_ok = self.count_real - self.count_notok
# if self.count_ok < 0:
# raise ParseError('合格数量不能小于0')
# self.save(update_fields=['count_ok', 'count_notok'])
# class FtestworkDefect(BaseModel):
# ftestwork = models.ForeignKey(FtestWork, verbose_name='关联检验工作', on_delete=models.CASCADE,
# related_name='ftestwork_defect')
# defect = models.ForeignKey(Defect, verbose_name='缺陷', on_delete=models.CASCADE)
# count = models.PositiveIntegerField('数量', default=0)
class Ftest(CommonBDModel): class Ftest(CommonBDModel):
""" """
检验记录 检验记录

View File

@ -4,7 +4,7 @@ from apps.qm.models import (QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptes
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
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError, ParseError
from apps.wpm.models import SfLog, WMaterial from apps.wpm.models import SfLog, WMaterial
from django.db import transaction from django.db import transaction
from apps.inm.serializers import MaterialBatchDetailSerializer from apps.inm.serializers import MaterialBatchDetailSerializer
@ -270,7 +270,7 @@ class FtestProcessSerializer(CustomModelSerializer):
class Meta: class Meta:
model = Ftest model = Ftest
fields = ["id", "test_date", fields = ["id", "test_date",
"test_user", "note", "ftestitems", "ftestdefects", "qct", "test_user_name", "wpr"] "test_user", "note", "ftestitems", "ftestdefects", "qct", "test_user_name"]
extra_kwargs = {"qct": {"required": True}} extra_kwargs = {"qct": {"required": True}}
def validate(self, attrs): def validate(self, attrs):
@ -300,19 +300,21 @@ class FtestProcessSerializer(CustomModelSerializer):
with transaction.atomic(): with transaction.atomic():
instance = super().update(instance, validated_data) instance = super().update(instance, validated_data)
for item in ftestitems: for item in ftestitems:
if "id" in item and item["id"]: try:
FtestItem.objects.filter(id=item["id"]).update( ins = FtestItem.objects.get(testitem = item["testitem"], ftest=instance)
test_user = item["test_user"], except FtestItem.DoesNotExist:
test_val_json = item["test_val_json"]) raise ParseError("新的检测项!")
else: for k, v in item.items():
FtestItem.objects.create(ftest=instance, **item) setattr(ins, k, v)
ins.save()
is_ok = True is_ok = True
for item2 in ftestdefects: for item2 in ftestdefects:
if "id" in item2 and item2["id"]: try:
ins: FtestDefect = FtestDefect.objects.get(id=item2["id"]) ins = FtestDefect.objects.get(ftest=instance, defect=item2["defect"])
else: except FtestDefect.DoesNotExist:
ins = FtestDefect.objects.create(ftest=instance, **item2) raise ParseError("新的缺陷项!")
ins.has = item2["has"] for k, v in item2.items():
setattr(ins, k, v)
ins.save() ins.save()
if ins.has and ins.defect.okcate in [Defect.DEFECT_NOTOK]: if ins.has and ins.defect.okcate in [Defect.DEFECT_NOTOK]:
is_ok = False is_ok = False

View File

@ -1,36 +0,0 @@
# Generated by Django 3.2.12 on 2025-01-08 07:01
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('qm', '0034_auto_20250108_1016'),
('wpm', '0083_mlogbw_ftest'),
]
operations = [
migrations.CreateModel(
name='MlogbDefect',
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='删除标记')),
('count', models.PositiveIntegerField(default=0, verbose_name='数量')),
('defect', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.defect', verbose_name='缺陷')),
('mlogb', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.mlogb', verbose_name='关联记录')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='mlogb',
name='defects',
field=models.ManyToManyField(blank=True, through='wpm.MlogbDefect', to='qm.Defect', verbose_name='不合格缺陷'),
),
]

View File

@ -344,33 +344,19 @@ class Mlogb(BaseModel):
count_n_zt = models.PositiveIntegerField('炸头', default=0) count_n_zt = models.PositiveIntegerField('炸头', default=0)
count_n_qt = models.PositiveIntegerField('其他', default=0) count_n_qt = models.PositiveIntegerField('其他', default=0)
count_notok_json = models.JSONField('不合格情况', default=list, blank=True) count_notok_json = models.JSONField('不合格情况', default=list, blank=True)
defects = models.ManyToManyField("qm.defect", verbose_name='不合格缺陷',
through="wpm.mlogbdefect", blank=True)
def get_tracking(self): def get_tracking(self):
if self.material_in: if self.material_in:
return "in", self.material_in.tracking return "in", self.material_in.tracking
elif self.material_out: elif self.material_out:
return "out", self.material_out.tracking return "out", self.material_out.tracking
def cal_count(self):
self.count_notok = MlogbDefect.objects.filter(
mlogb=self, defect__okcate=30).aggregate(total=Sum("count"))["total"] or 0
self.count_ok = self.count_real - self.count_notok
if self.count_ok < 0:
raise ParseError('合格数量不能小于0')
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 = models.PositiveIntegerField('数量', default=0)
class Mlogbw(BaseModel): class Mlogbw(BaseModel):
number = models.TextField('单个编号') number = models.TextField('单个编号')
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) ftest = models.OneToOneField("qm.ftest", verbose_name='关联检验',
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)

View File

@ -6,7 +6,7 @@ from datetime import datetime
from .models import (SfLog, StLog, SfLogExp, WMaterial, Mlog, from .models import (SfLog, StLog, SfLogExp, WMaterial, Mlog,
Handover, Handoverb, Mlogb, AttLog, Handover, Handoverb, Mlogb, AttLog,
OtherLog, Fmlog, BatchSt, Mlogbw, Handoverbw, MlogbDefect) OtherLog, Fmlog, BatchSt, Mlogbw, Handoverbw)
from apps.system.models import Dept, User from apps.system.models import Dept, User
from apps.system.serializers import UserSimpleSerializer from apps.system.serializers import UserSimpleSerializer
from apps.pm.models import Mtask, Mtaskb from apps.pm.models import Mtask, Mtaskb
@ -591,14 +591,15 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer):
return attrs return attrs
def save_ftest(self, mlogbw, ftest_data): def save_ftest(self, mlogbw, ftest_data):
if "id" not in ftest_data or not ftest_data["id"]: ftest = mlogbw.ftest
if not ftest:
ftest_sr = FtestProcessSerializer(data=ftest_data) ftest_sr = FtestProcessSerializer(data=ftest_data)
ftest = ftest_sr.create(ftest_data) ftest = ftest_sr.create(ftest_data)
mlogbw.ftest = ftest mlogbw.ftest = ftest
mlogbw.save() mlogbw.save()
else: else:
ftest_sr = FtestProcessSerializer() ftest_sr = FtestProcessSerializer()
ftest_sr.update(instance=Ftest.objects.get(id=ftest_data["id"]), validated_data=ftest_data) ftest_sr.update(instance=ftest, validated_data=ftest_data)
return mlogbw return mlogbw
@transaction.atomic @transaction.atomic
@ -908,16 +909,3 @@ class BatchStSerializer(CustomModelSerializer):
model = BatchSt model = BatchSt
fields = "__all__" fields = "__all__"
class MlogbDefectSerializer(CustomModelSerializer):
defect_name = serializers.CharField(source='defect.name', read_only=True)
class Meta:
model = MlogbDefect
fields = "__all__"
read_only_fields = EXCLUDE_FIELDS_BASE
def create(self, validated_data):
defect = validated_data["defect"]
mlogb = validated_data["mlogb"]
if MlogbDefect.objects.filter(mlogb=mlogb, defect=defect).exists():
raise ParseError('该缺陷已填写')
return super().create(validated_data)

View File

@ -201,6 +201,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]):
if mlogbws.count() != mi_count: if mlogbws.count() != mi_count:
raise ParseError("日志与明细数量不一致,操作失败") raise ParseError("日志与明细数量不一致,操作失败")
for item in mlogbws: for item in mlogbws:
if item.test:
raise ParseError("不支持消耗物料的检验")
Wpr.change_or_new(wpr=item.wpr, old_wm=wm) Wpr.change_or_new(wpr=item.wpr, old_wm=wm)
# 针对加工前不良的暂时额外处理 # 针对加工前不良的暂时额外处理

View File

@ -5,7 +5,7 @@ from apps.wpm.views import (SfLogViewSet, StLogViewSet, SfLogExpViewSet,
WMaterialViewSet, MlogViewSet, HandoverViewSet, WMaterialViewSet, MlogViewSet, HandoverViewSet,
AttlogViewSet, OtherLogViewSet, MlogbViewSet, MlogbInViewSet, AttlogViewSet, OtherLogViewSet, MlogbViewSet, MlogbInViewSet,
MlogbOutViewSet, FmlogViewSet, BatchStViewSet, MlogbOutViewSet, FmlogViewSet, BatchStViewSet,
MlogbwViewSet, MlogbDefectViewSet) MlogbwViewSet)
from apps.wpm.datax import AnaViewSet from apps.wpm.datax import AnaViewSet
@ -28,7 +28,6 @@ router.register('otherlog', OtherLogViewSet, basename='otherlog')
router.register('ana', AnaViewSet, basename='ana') router.register('ana', AnaViewSet, basename='ana')
router.register('batchst', BatchStViewSet, basename='batchst') router.register('batchst', BatchStViewSet, basename='batchst')
router.register('mlogbw', MlogbwViewSet, basename='mlogbw') router.register('mlogbw', MlogbwViewSet, basename='mlogbw')
router.register("mlogbdefect", MlogbDefectViewSet, basename='mlogbdefect')
urlpatterns = [ urlpatterns = [
path(API_BASE_URL, include(router.urls)), path(API_BASE_URL, include(router.urls)),
] ]

View File

@ -16,7 +16,7 @@ from apps.utils.mixins import CustomListModelMixin, BulkCreateModelMixin, BulkDe
from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter
from .models import (SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb, from .models import (SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb,
Mlogbw, AttLog, OtherLog, Fmlog, BatchSt, MlogbDefect) Mlogbw, AttLog, OtherLog, Fmlog, BatchSt)
from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer, from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer,
MlogRevertSerializer, MlogRevertSerializer,
MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer, MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer,
@ -25,7 +25,7 @@ from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer,
AttLogSerializer, OtherLogSerializer, MlogInitSerializer, MlogChangeSerializer, AttLogSerializer, OtherLogSerializer, MlogInitSerializer, MlogChangeSerializer,
MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer, MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer,
MlogbOutUpdateSerializer, FmlogSerializer, FmlogUpdateSerializer, BatchStSerializer, MlogbOutUpdateSerializer, FmlogSerializer, FmlogUpdateSerializer, BatchStSerializer,
MlogbwCreateUpdateSerializer, MlogbDefectSerializer) MlogbwCreateUpdateSerializer)
from .services import mlog_submit, handover_submit, mlog_revert from .services import mlog_submit, handover_submit, mlog_revert
from apps.wpm.services import mlog_submit_validate, generate_new_batch from apps.wpm.services import mlog_submit_validate, generate_new_batch
from apps.wf.models import State from apps.wf.models import State
@ -507,7 +507,7 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust
# 找寻质检表 # 找寻质检表
qctmat0 = QctMat.objects.filter(material=mlogbin.material_in).order_by("-create_time").first() qctmat0 = QctMat.objects.filter(material=mlogbin.material_in).order_by("-create_time").first()
if qctmat0: if qctmat0:
mlogbin.qct = qctmat0 mlogbin.qct = qctmat0.qct
mlogbin.save() mlogbin.save()
mlog:Mlog = mlogbin.mlog mlog:Mlog = mlogbin.mlog
route:Route = mlog.route route:Route = mlog.route
@ -618,8 +618,8 @@ class MlogbwViewSet(CustomModelViewSet):
mlogb.count_use = count mlogb.count_use = count
elif mlogb.material_out: elif mlogb.material_out:
mlogb.count_real = count mlogb.count_real = count
mlogb.count_ok = count mlogb.count_notok = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).count()
mlogb.count_notok = 0 mlogb.count_ok = count - mlogb.count_notok
mlogb.save() mlogb.save()
@transaction.atomic @transaction.atomic
@ -639,13 +639,15 @@ 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)
@transaction.atomic @transaction.atomic
def perform_destroy(self, instance:Mlogbw): def perform_destroy(self, instance:Mlogbw):
mlogb = instance.mlogb mlogb = instance.mlogb
if instance.ftest: ftest = instance.ftest
instance.ftest.delete()
instance.delete() instance.delete()
if ftest:
ftest.delete()
self.cal_mlogb_count(mlogb) self.cal_mlogb_count(mlogb)
# 如果是输入且输出追踪到个,需同步删除 # 如果是输入且输出追踪到个,需同步删除
material_in: Material = mlogb.material_in material_in: Material = mlogb.material_in
@ -658,28 +660,3 @@ class MlogbwViewSet(CustomModelViewSet):
mbw.ftest.delete() mbw.ftest.delete()
mbw.delete() mbw.delete()
self.cal_mlogb_count(mlogb_to) self.cal_mlogb_count(mlogb_to)
class MlogbDefectViewSet(CustomListModelMixin, BulkCreateModelMixin,
BulkDestroyModelMixin, CustomGenericViewSet):
perms_map = {"get": "*", "post": "mlog.update", "delete": "mlog.update"}
queryset = MlogbDefect.objects.all()
serializer_class = MlogbDefectSerializer
filterset_fields = ["mlogb", "defect"]
ordering = ["create_time"]
def filter_queryset(self, queryset):
if not self.detail and not self.request.query_params.get('mlogb', None):
raise ParseError('请指定所属日志明细')
return super().filter_queryset(queryset)
@transaction.atomic
def perform_create(self, serializer):
ins:MlogbDefect = serializer.save()
ins.mlogb.cal_count()
@transaction.atomic
def perform_destroy(self, instance):
mlogb = instance.mlogb
instance.delete()
mlogb.cal_count()