diff --git a/apps/qm/models.py b/apps/qm/models.py index 0d547a28..32110ff3 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -235,6 +235,20 @@ class FtestWork(CommonBDModel): ftestwork_count_fields.append(f.name) 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): """ 检验记录 diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index 842fffa6..5cd71303 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -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.serializers import CustomModelSerializer 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 django.db import transaction from apps.inm.serializers import MaterialBatchDetailSerializer @@ -270,7 +270,7 @@ class FtestProcessSerializer(CustomModelSerializer): class Meta: model = Ftest 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}} def validate(self, attrs): @@ -300,19 +300,21 @@ class FtestProcessSerializer(CustomModelSerializer): 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) + try: + ins = FtestItem.objects.get(testitem = item["testitem"], ftest=instance) + except FtestItem.DoesNotExist: + raise ParseError("新的检测项!") + for k, v in item.items(): + setattr(ins, k, v) + ins.save() 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"] + try: + ins = FtestDefect.objects.get(ftest=instance, defect=item2["defect"]) + except FtestDefect.DoesNotExist: + raise ParseError("新的缺陷项!") + for k, v in item2.items(): + setattr(ins, k, v) ins.save() if ins.has and ins.defect.okcate in [Defect.DEFECT_NOTOK]: is_ok = False diff --git a/apps/wpm/migrations/0084_auto_20250108_1501.py b/apps/wpm/migrations/0084_auto_20250108_1501.py deleted file mode 100644 index b5b43404..00000000 --- a/apps/wpm/migrations/0084_auto_20250108_1501.py +++ /dev/null @@ -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='不合格缺陷'), - ), - ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index b41b4127..f95d8123 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -344,33 +344,19 @@ class Mlogb(BaseModel): count_n_zt = models.PositiveIntegerField('炸头', default=0) count_n_qt = models.PositiveIntegerField('其他', default=0) 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): if self.material_in: return "in", self.material_in.tracking elif self.material_out: 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): number = models.TextField('单个编号') mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE) wpr = models.ForeignKey("wpmw.wpr", verbose_name='关联产品', on_delete=models.SET_NULL , 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) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index ea1451a5..ca29e518 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -6,7 +6,7 @@ from datetime import datetime from .models import (SfLog, StLog, SfLogExp, WMaterial, Mlog, 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.serializers import UserSimpleSerializer from apps.pm.models import Mtask, Mtaskb @@ -591,14 +591,15 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer): return attrs 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 = ftest_sr.create(ftest_data) mlogbw.ftest = ftest mlogbw.save() else: 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 @transaction.atomic @@ -908,16 +909,3 @@ class BatchStSerializer(CustomModelSerializer): model = BatchSt 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) \ No newline at end of file diff --git a/apps/wpm/services.py b/apps/wpm/services.py index f27e3f4b..36a6d14b 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -201,6 +201,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): if mlogbws.count() != mi_count: raise ParseError("日志与明细数量不一致,操作失败") for item in mlogbws: + if item.test: + raise ParseError("不支持消耗物料的检验") Wpr.change_or_new(wpr=item.wpr, old_wm=wm) # 针对加工前不良的暂时额外处理 diff --git a/apps/wpm/urls.py b/apps/wpm/urls.py index d64e046d..406d0280 100644 --- a/apps/wpm/urls.py +++ b/apps/wpm/urls.py @@ -5,7 +5,7 @@ from apps.wpm.views import (SfLogViewSet, StLogViewSet, SfLogExpViewSet, WMaterialViewSet, MlogViewSet, HandoverViewSet, AttlogViewSet, OtherLogViewSet, MlogbViewSet, MlogbInViewSet, MlogbOutViewSet, FmlogViewSet, BatchStViewSet, - MlogbwViewSet, MlogbDefectViewSet) + MlogbwViewSet) from apps.wpm.datax import AnaViewSet @@ -28,7 +28,6 @@ router.register('otherlog', OtherLogViewSet, basename='otherlog') router.register('ana', AnaViewSet, basename='ana') router.register('batchst', BatchStViewSet, basename='batchst') router.register('mlogbw', MlogbwViewSet, basename='mlogbw') -router.register("mlogbdefect", MlogbDefectViewSet, basename='mlogbdefect') urlpatterns = [ path(API_BASE_URL, include(router.urls)), ] diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 66a555d3..d45191c3 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -16,7 +16,7 @@ from apps.utils.mixins import CustomListModelMixin, BulkCreateModelMixin, BulkDe from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter 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, MlogRevertSerializer, MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer, @@ -25,7 +25,7 @@ from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, AttLogSerializer, OtherLogSerializer, MlogInitSerializer, MlogChangeSerializer, MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer, MlogbOutUpdateSerializer, FmlogSerializer, FmlogUpdateSerializer, BatchStSerializer, - MlogbwCreateUpdateSerializer, MlogbDefectSerializer) + MlogbwCreateUpdateSerializer) from .services import mlog_submit, handover_submit, mlog_revert from apps.wpm.services import mlog_submit_validate, generate_new_batch 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() if qctmat0: - mlogbin.qct = qctmat0 + mlogbin.qct = qctmat0.qct mlogbin.save() mlog:Mlog = mlogbin.mlog route:Route = mlog.route @@ -618,8 +618,8 @@ class MlogbwViewSet(CustomModelViewSet): mlogb.count_use = count elif mlogb.material_out: mlogb.count_real = count - mlogb.count_ok = count - mlogb.count_notok = 0 + mlogb.count_notok = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).count() + mlogb.count_ok = count - mlogb.count_notok mlogb.save() @transaction.atomic @@ -639,13 +639,15 @@ class MlogbwViewSet(CustomModelViewSet): @transaction.atomic def perform_update(self, serializer): mlogbw = serializer.save() + self.cal_mlogb_count(mlogbw.mlogb) @transaction.atomic def perform_destroy(self, instance:Mlogbw): mlogb = instance.mlogb - if instance.ftest: - instance.ftest.delete() + ftest = instance.ftest instance.delete() + if ftest: + ftest.delete() self.cal_mlogb_count(mlogb) # 如果是输入且输出追踪到个,需同步删除 material_in: Material = mlogb.material_in @@ -658,28 +660,3 @@ class MlogbwViewSet(CustomModelViewSet): mbw.ftest.delete() mbw.delete() 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() \ No newline at end of file