From 38dc9199e2961082f7a9211c00f76de16ea851e2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 13 Mar 2025 16:33:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0099_auto_20250313_1633.py | 41 +++++ apps/wpm/models.py | 10 +- apps/wpm/serializers.py | 4 +- apps/wpm/views.py | 158 +++++++----------- 4 files changed, 105 insertions(+), 108 deletions(-) create mode 100644 apps/wpm/migrations/0099_auto_20250313_1633.py diff --git a/apps/wpm/migrations/0099_auto_20250313_1633.py b/apps/wpm/migrations/0099_auto_20250313_1633.py new file mode 100644 index 00000000..8cff2b7b --- /dev/null +++ b/apps/wpm/migrations/0099_auto_20250313_1633.py @@ -0,0 +1,41 @@ +# Generated by Django 3.2.12 on 2025-03-13 08:33 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0098_auto_20250312_0923'), + ] + + operations = [ + migrations.RemoveField( + model_name='mlogb', + name='mlogb_to', + ), + migrations.RemoveField( + model_name='mlogbw', + name='mlogb_to', + ), + migrations.RemoveField( + model_name='mlogbw', + name='mlogbw_to', + ), + migrations.AddField( + model_name='mlogb', + name='mlogb_from', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlogb_from_mlogb', to='wpm.mlogb', verbose_name='来源批'), + ), + migrations.AddField( + model_name='mlogb', + name='mlogbw_from', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlogb_from_mlogb', to='wpm.mlogbw', verbose_name='来源个'), + ), + migrations.AlterField( + model_name='mlogbw', + name='mlogbw_from', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='w_mlogbw_from', to='wpm.mlogbw', verbose_name='来源个'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 4232be25..fb6ca3ec 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -329,8 +329,10 @@ class Mlogb(BaseModel): parent = models.ForeignKey("self", verbose_name='父级物料', on_delete=models.CASCADE, null=True, blank=True, related_name='mlogb_parent') - mlogb_to = models.ForeignKey("self", verbose_name='生成的', on_delete=models.SET_NULL, null=True, blank=True, - related_name='mlogb_to_mlogb') + mlogb_from = models.ForeignKey("self", verbose_name='来源批', on_delete=models.CASCADE, null=True, blank=True, + related_name='mlogb_from_mlogb') + mlogbw_from = models.ForeignKey("wpm.mlogbw", verbose_name='来源个', on_delete=models.CASCADE, null=True, blank=True, + related_name='mlogb_from_mlogb') material_out = models.ForeignKey( Material, verbose_name='产物', on_delete=models.CASCADE, related_name='mlogb_material_out', null=True, blank=True) @@ -435,9 +437,7 @@ class Mlogbw(BaseModel): """ number = models.TextField('单个编号') mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE, related_name="w_mlogb") - mlogb_to = models.ForeignKey(Mlogb, verbose_name='指向生产记录', on_delete=models.CASCADE, null=True, blank=True, related_name="w_mlogb_to") - mlogbw_to = models.ForeignKey("self", verbose_name='指向单个产品', on_delete=models.SET_NULL, null=True, blank=True, related_name="w_mlogbw_to") - mlogbw_from = models.ForeignKey("self", verbose_name='来自单个产品', on_delete=models.SET_NULL, null=True, blank=True, related_name="w_mlogbw_from") + mlogbw_from = models.ForeignKey("self", verbose_name='来源个', on_delete=models.CASCADE, null=True, blank=True, related_name="w_mlogbw_from") wpr = models.ForeignKey("wpmw.wpr", verbose_name='关联产品', on_delete=models.SET_NULL , related_name='wpr_mlogbw', null=True, blank=True) equip = models.ForeignKey(Equipment, verbose_name='设备', on_delete=models.SET_NULL, null=True, blank=True) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 4b5ab5ff..b0c8a6a1 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -732,8 +732,8 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer): ftest = FtestProcessSerializer(required=False) class Meta: model = Mlogbw - fields = ["id", "number", "wpr", "note", "mlogb", "ftest", "equip", "work_start_time", "work_end_time", "mlogb_to"] - read_only_fields = ["mlogb_to"] + fields = ["id", "number", "wpr", "note", "mlogb", "ftest", "equip", "work_start_time", "work_end_time", "mlogb_from", "mlogbw_from"] + read_only_fields = ["mlogb_from", "mlogbw_from"] def validate(self, attrs): mlogb:Mlogb = attrs["mlogb"] diff --git a/apps/wpm/views.py b/apps/wpm/views.py index dc2f255b..78e1647e 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -539,32 +539,6 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust ins: Mlogb = instance if ins.mlog.submit_time is not None: raise ParseError('生产日志已提交不可编辑') - # if ins.mlogb_to: - # qs = Mlogb.objects.filter(id=ins.mlogb_to.id) - # ftestIds = list(Ftest.objects.filter(mlogbw_ftest__mlogb__in=qs).values_list('id', flat=True)) - # qs.delete() - # if ftestIds: - # Ftest.objects.filter(id__in=ftestIds).delete() - # elif ins.parent is None and ins.mtask: - # query_dict = {"material_out__isnull": False, "mlog": ins.mlog, "mtask": ins.mtask} - # route = ins.mtask.route - # if route.batch_bind: - # query_dict["batch__contains"] = ins.batch - # qs = Mlogb.objects.filter(**query_dict) - qs = Mlogbw.objects.filter(mlogb=ins, ftest__isnull=False) - if ins.mlogb_to: - qs = qs|Mlogbw.objects.filter(mlogb=ins.mlogb_to, ftest__isnull=False) - qs = qs|Mlogbw.objects.filter(mlogb__id__in=list(Mlogbw.objects.filter(mlogb=ins).values_list("mlogb_to__id", flat=True)), ftest__isnull=False) - # 需要删除子集ftest记录 - if qs: - ftestIds = list(Ftest.objects.filter(mlogbw_ftest__in=qs).values_list('id', flat=True)) - qs.delete() - if ftestIds: - Ftest.objects.filter(id__in=ftestIds).delete() - if ins.mlogb_to: - ins.mlogb_to.delete() - mlogb_to_ids = list(Mlogbw.objects.filter(mlogb=ins).values_list("mlogb_to__id", flat=True)) - Mlogb.objects.filter(id__in=mlogb_to_ids).delete() ins.delete() @transaction.atomic @@ -610,11 +584,9 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust d_count_real = mlogbin.count_use d_count_ok = mlogbin.count_use mlogbout, _ = Mlogb.objects.get_or_create(**m_dict, defaults= - {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, "count_real": d_count_real, "count_ok": d_count_ok, "qct": qct}) - if mlogbin.mlogb_to is None: - mlogbin.mlogb_to = mlogbout - mlogbin.save(update_fields = ["mlogb_to"]) - elif mlogbin.mlogb_to != mlogbout: + {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, "count_real": d_count_real, "count_ok": d_count_ok, + "qct": qct, "mlogb_from": mlogbin}) + if mlogbout.mlogb_from != mlogbin: raise ParseError("生成产出出错1") elif mtype == Process.PRO_DIV: div_number = route.div_number @@ -622,42 +594,34 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust for mlogbwin in Mlogbw.objects.filter(mlogb=mlogbin).order_by("number"): m_dict["batch"] = mlogbwin.number mlogbout, _ = Mlogb.objects.get_or_create(**m_dict, defaults= - {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, "count_real": div_number, "count_ok": div_number, "qct": qct}) - if mlogbwin.mlogb_to is None: - mlogbwin.mlogb_to = mlogbout - mlogbwin.save(update_fields = ["mlogb_to"]) - elif mlogbwin.mlogb_to != mlogbout: + {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, + "count_real": div_number, "count_ok": div_number, "qct": qct, "mlogbw_from": mlogbwin}) + if mlogbout.mlogbw_from != mlogbwin: raise ParseError("生成产出出错2") elif material_out.tracking == Material.MA_TRACKING_BATCH: d_count_real = mlogbin.count_use * div_number d_count_ok = d_count_real mlogbout, _ = Mlogb.objects.get_or_create(**m_dict, defaults= - {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, "count_real": d_count_real, "count_ok": d_count_ok, "qct": qct}) - if mlogbin.mlogb_to is None: - mlogbin.mlogb_to = mlogbout - mlogbin.save(update_fields = ["mlogb_to"]) - elif mlogbin.mlogb_to != mlogbout: + {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, + "count_real": d_count_real, "count_ok": d_count_ok, "qct": qct, "mlogb_from": mlogbin}) + if mlogbout.mlogb_from != mlogbin: raise ParseError("生成产出出错2-2") elif mtype == Process.PRO_MERGE: xcount = math.floor( mlogbin.count_use / route.div_number) d_count_real = xcount d_count_ok = xcount mlogbout, _ = Mlogb.objects.get_or_create(**m_dict, defaults= - {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, "count_real": d_count_real, "count_ok": d_count_ok, "qct": qct}) - if mlogbin.mlogb_to is None: - mlogbin.mlogb_to = mlogbout - mlogbin.save(update_fields = ["mlogb_to"]) - elif mlogbin.mlogb_to != mlogbout: + {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, + "count_real": d_count_real, "count_ok": d_count_ok, "qct": qct, "mlogb_from": mlogbin}) + if mlogbout.mlogb_from != mlogbin: raise ParseError("生成产出出错3") elif is_fix: d_count_real = mlogbin.count_use d_count_ok = mlogbin.count_use mlogbout, _ = Mlogb.objects.get_or_create(**m_dict, defaults= - {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, "count_real": d_count_real, "count_ok": d_count_ok, "qct": qct}) - if mlogbin.mlogb_to is None: - mlogbin.mlogb_to = mlogbout - mlogbin.save(update_fields = ["mlogb_to"]) - elif mlogbin.mlogb_to != mlogbout: + {"batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, + "count_real": d_count_real, "count_ok": d_count_ok, "qct": qct, "mlogb_from": mlogbin}) + if mlogbout.mlogb_from != mlogbin: raise ParseError("生成产出出错4") else: raise ParseError("不支持生成产出物料!") @@ -666,21 +630,15 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust for mlogbwin in Mlogbw.objects.filter(mlogb=mlogbin).order_by("number"): wpr = mlogbwin.wpr if mtype == Process.PRO_NORMAL: - bw, _ = Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbout, defaults={"number": wpr.number}) - if mlogbwin.mlogbw_to is None: - mlogbwin.mlogbw_to = bw - mlogbwin.save(update_fields = ["mlogbw_to"]) - elif mlogbwin.mlogbw_to != bw: + bw, _ = Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbout, defaults={"number": wpr.number, "mlogbw_from": mlogbwin}) + if bw.mlogbw_from != mlogbwin: raise ParseError("生成产出出错5") elif mtype == Process.PRO_DIV: for i in range(route.div_number): Mlogbw.objects.get_or_create(mlogb=mlogbout, number=f'{wpr.number}-{i+1}', defaults={"mlogbw_from": mlogbwin}) elif is_fix: - bw, _ = Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbout, defaults={"number": wpr.number}) - if mlogbwin.mlogbw_to is None: - mlogbwin.mlogbw_to = bw - mlogbwin.save(update_fields = ["mlogbw_to"]) - elif mlogbwin.mlogbw_to != bw: + bw, _ = Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbout, defaults={"number": wpr.number, "mlogbw_from": mlogbwin}) + if bw.mlogbw_from != mlogbwin: raise ParseError("生成产出出错6") else: raise ParseError("不支持的生产类型1") @@ -749,7 +707,7 @@ class MlogbwViewSet(CustomModelViewSet): # 如果是输入且输出追踪到个,需同步创建 material_in:Material = mlogb.material_in if material_in is not None: - mlogb_to = mlogb.mlogb_to + mlogb_qs = Mlogb.objects.filter(mlogb_from=ins) material_out:Material = mlogb.mlog.material_out mtype = route.process.mtype if route.process else None if material_in.tracking == Material.MA_TRACKING_SINGLE and mtype == Process.PRO_DIV: @@ -757,38 +715,31 @@ class MlogbwViewSet(CustomModelViewSet): wm_in = mlogbin.wm_in mlog = mlogbin.mlog div_number = route.div_number - if ins.mlogb_to: - mlogbout = ins.mlogb_to - else: - m_dict = { - "mtask": mlogbin.mtask, - "mlog": mlog, - "batch": ins.number, - "material_out": material_out, - "batch_ofrom": wm_in.batch_ofrom, - "material_ofrom": wm_in.material_ofrom, - "count_real": div_number, - "count_ok": div_number, "qct": mlog.qct - } - mlogbout = Mlogb.objects.create(**m_dict) - ins.mlogb_to = mlogbout - ins.save(update_fields=["mlogb_to"]) + m_dict = { + "mtask": mlogbin.mtask, + "mlog": mlog, + "batch": ins.number, + "material_out": material_out, + "batch_ofrom": wm_in.batch_ofrom, + "material_ofrom": wm_in.material_ofrom, + "count_real": div_number, + "count_ok": div_number, "qct": mlog.qct + } + mlogbout, _ = Mlogb.objects.get_or_create(mlogbw_from=ins, defaults=m_dict) if material_out.tracking == Material.MA_TRACKING_SINGLE: for i in range(div_number): Mlogbw.objects.get_or_create(mlogb=mlogbout, number=f"{ins.number}-{i+1}", defaults={"mlogbw_from": ins}) Mlogbw.cal_count_notok(mlogbout) - elif mlogb_to and material_out.tracking == Material.MA_TRACKING_SINGLE: - if route.process.mtype == Process.PRO_NORMAL: - bw, _ = Mlogbw.objects.get_or_create(mlogb=mlogb_to, wpr=ins.wpr, defaults={"number": ins.number}) - if ins.mlogbw_to is None: - ins.mlogbw_to = bw - ins.save(update_fields=["mlogbw_to"]) - elif ins.mlogbw_to != bw: - raise ParseError("生成产出出错7") - elif route.process.mtype == Process.PRO_DIV: - for i in range(route.div_number): - Mlogbw.objects.get_or_create(mlogb=mlogb_to, number=f'{ins.number}-{i+1}', defaults={"mlogbw_from": ins}) - Mlogbw.cal_count_notok(mlogb_to) + elif mlogb_qs.exists() and material_out.tracking == Material.MA_TRACKING_SINGLE: + for mlogb in mlogb_qs: + if route.process.mtype == Process.PRO_NORMAL: + bw, _ = Mlogbw.objects.get_or_create(mlogb=mlogb, wpr=ins.wpr, defaults={"number": ins.number, "mlogbw_from": ins}) + if bw.mlogbw_from != ins: + raise ParseError("生成产出出错7") + elif route.process.mtype == Process.PRO_DIV: + for i in range(route.div_number): + Mlogbw.objects.get_or_create(mlogb=mlogb, number=f'{ins.number}-{i+1}', defaults={"mlogbw_from": ins}) + Mlogbw.cal_count_notok(mlogb) @transaction.atomic def perform_update(self, serializer): @@ -801,17 +752,22 @@ class MlogbwViewSet(CustomModelViewSet): if mlogb.material_out is not None and instance.wpr is not None: raise ParseError("不能删除该产出明细") - ftest = instance.ftest - instance.delete() - if ftest: - ftest.delete() - Mlogbw.cal_count_notok(mlogb) - # 如果是输入且输出追踪到个,需同步删除 material_in: Material = mlogb.material_in + need_cal_mlogb = False if material_in is not None: - if instance.mlogb_to: - Mlogb.objects.filter(id=instance.mlogb_to.id).delete() - if instance.mlogbw_to: - instance.mlogbw_to.delete() - Mlogbw.cal_count_notok(instance.mlogbw_to.mlogb) + mlogbw_qs = Mlogbw.objects.filter(mlogbw_from=instance) + mlogbIds = list(mlogbw_qs.values_list("mlogb__id", flat=True)) + if mlogbIds: + need_cal_mlogb = True + + + ftest = instance.ftest + if ftest: + ftest.delete() + instance.delete() + Mlogbw.cal_count_notok(mlogb) + + if need_cal_mlogb: + for i in mlogbIds: + Mlogbw.cal_count_notok(Mlogb.objects.get(id=i)) \ No newline at end of file