From b2f801deda86b8c19bf804508fc0ec78d5c13b4a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 28 Feb 2025 09:14:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0mlogbdefect?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/migrations/0089_mlogbdefect.py | 31 +++++++ apps/wpm/models.py | 10 +++ apps/wpm/serializers.py | 114 ++++++++++++++++++------ apps/wpm/services.py | 2 + 4 files changed, 129 insertions(+), 28 deletions(-) create mode 100644 apps/wpm/migrations/0089_mlogbdefect.py diff --git a/apps/wpm/migrations/0089_mlogbdefect.py b/apps/wpm/migrations/0089_mlogbdefect.py new file mode 100644 index 00000000..feaaa309 --- /dev/null +++ b/apps/wpm/migrations/0089_mlogbdefect.py @@ -0,0 +1,31 @@ +# Generated by Django 3.2.12 on 2025-02-28 01:11 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0044_testitem_cd_expr'), + ('wpm', '0088_auto_20250224_0938'), + ] + + 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, + }, + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 3b1a9745..8cb6e55a 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -357,6 +357,16 @@ class Mlogb(BaseModel): return "in", self.material_in.tracking elif self.material_out: return "out", self.material_out.tracking + + @property + def mlogbdefect(self): + return MlogbDefect.objects.filter(mlogb=self) + + +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): """TN: 单个产品生产/检验日志 diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index b2c725db..b20f1285 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) + OtherLog, Fmlog, BatchSt, Mlogbw, Handoverbw, MlogbDefect) from apps.system.models import Dept, User from apps.system.serializers import UserSimpleSerializer from apps.pm.models import Mtask, Mtaskb @@ -23,6 +23,7 @@ from apps.wf.serializers import TicketSimpleSerializer from apps.wpmw.models import Wpr from apps.qm.serializers import FtestProcessSerializer import logging +from apps.qm.models import Defect mylogger = logging.getLogger("log") class OtherLogSerializer(CustomModelSerializer): @@ -687,42 +688,99 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer): mlogbw = self.save_ftest(mlogbw, ftest_data) return mlogbw +class MlogbDefectSerializer(CustomModelSerializer): + defect_name = serializers.CharField(source="defect.name", read_only=True) + class Meta: + model = Mlogb + fields = ["id", "defect_name", "count", "mlogb", "defect"] + class MlogbOutUpdateSerializer(CustomModelSerializer): + mlogbdefect = MlogbDefectSerializer(many=True, required=False) + class Meta: model = Mlogb fields = "__all__" read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', - 'count_use', 'count_break', 'count_pn_jgqbl'] + 'count_use', 'count_break', 'count_pn_jgqbl', 'mlogbdefect'] + + def create(self, validated_data): + material_out:Material = validated_data["material_out"] + mlogbdefect = validated_data.pop("mlogbdefect", []) + with transaction.atomic(): + ins = super().create(validated_data) + if mlogbdefect and material_out.tracking == Material.MA_TRACKING_BATCH: + count_notok = 0 + mlogbdefect_new = [item for item in mlogbdefect if item["count"] > 0] + for item in mlogbdefect_new: + defect:Defect = item["defect"] + Mlogb.objects.create(mlogb=ins, defect=defect, count=item["count"]) + if defect.cate == Defect.DEFECT_NOTOK: + count_notok +=1 + ins.count_notok = count_notok + ins.count_ok = ins.count_real - ins.count_notok + ins.save() + else: + raise ParseError("mlogbdefect仅支持批次件") + return ins + + def update(self, instance, validated_data): + material_out:Material = validated_data["material_out"] + mlogbdefect = validated_data.pop("mlogbdefect", []) + with transaction.atomic(): + ins:Mlogb = super().update(instance, validated_data) + if mlogbdefect and material_out.tracking == Material.MA_TRACKING_BATCH: + defectIds = [item["defect"].id for item in mlogbdefect if item["count"] > 0] + Mlogb.objects.filter(mlogb=ins).exclude(defect_id__in=defectIds).delete() + count_notok = 0 + for item in mlogbdefect: + defect = item["defect"] + insb = MlogbDefect.objects.get(mlogb=ins, defect=defect) + insb.count = item["count"] + insb.save(update_fields=["count"]) + if defect.cate == Defect.DEFECT_NOTOK: + count_notok +=1 + ins.count_notok = count_notok + ins.count_ok = ins.count_real + ins.save() + return ins def validate(self, attrs): - count_notok_json = attrs.get('count_notok_json', []) - # count_notok_json字段处理 - if count_notok_json: - # 先置0字段 + mlogbdefect = attrs.get("mlogbdefect", []) + if mlogbdefect: + pass + # attrs.pop("count_notok_json") + # for i in attrs: + # if 'count_n_' in i: + # attrs.pop(i, None) + else: + count_notok_json = attrs.get('count_notok_json', []) + # count_notok_json字段处理 + if count_notok_json: + # 先置0字段 + for i in attrs: + if 'count_n_' in i: + i = 0 + count_notok_dict = {} + for item in count_notok_json: + notok = item['notok'] + count = item['count'] + full_notok = f'count_n_{notok}' + if not hasattr(Mlogb, full_notok): + raise ParseError(f'{notok}-该不合格项不存在') + if full_notok in count_notok_dict: + count_notok_dict[full_notok] = count_notok_dict[full_notok] + count + else: + count_notok_dict[full_notok] = count + for k, v in count_notok_dict.items(): + attrs[k] = v + + count_notok = 0 for i in attrs: if 'count_n_' in i: - i = 0 - count_notok_dict = {} - for item in count_notok_json: - notok = item['notok'] - count = item['count'] - full_notok = f'count_n_{notok}' - if not hasattr(Mlogb, full_notok): - raise ParseError(f'{notok}-该不合格项不存在') - if full_notok in count_notok_dict: - count_notok_dict[full_notok] = count_notok_dict[full_notok] + count - else: - count_notok_dict[full_notok] = count - for k, v in count_notok_dict.items(): - attrs[k] = v - - count_notok = 0 - for i in attrs: - if 'count_n_' in i: - if not hasattr(Mlogb, i): - raise ParseError(f'{i}不存在') - count_notok = count_notok + attrs[i] - attrs['count_notok'] = count_notok + if not hasattr(Mlogb, i): + raise ParseError(f'{i}不存在') + count_notok = count_notok + attrs[i] + attrs['count_notok'] = count_notok if attrs['count_real'] >= attrs['count_ok'] + attrs['count_notok']: pass else: diff --git a/apps/wpm/services.py b/apps/wpm/services.py index e5332027..80b3254b 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -170,6 +170,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): for mi in m_ins.all(): m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi)) if mi.count_pn_jgqbl > 0: + raise ParseError("暂不支持加工前不良") m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_pn_jgqbl, mi)) else: m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog)] @@ -446,6 +447,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): for mi in m_ins.all(): m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi.wm_in, mi)) if mi.count_pn_jgqbl > 0: + raise ParseError("暂不支持加工前不良") m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_pn_jgqbl, mi)) else: m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in, mlog)]