diff --git a/apps/wpm/migrations/0098_auto_20250312_0923.py b/apps/wpm/migrations/0098_auto_20250312_0923.py new file mode 100644 index 00000000..94102db9 --- /dev/null +++ b/apps/wpm/migrations/0098_auto_20250312_0923.py @@ -0,0 +1,24 @@ +# Generated by Django 3.2.12 on 2025-03-12 01:23 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0097_auto_20250310_1746'), + ] + + operations = [ + migrations.AddField( + model_name='mlogbw', + name='mlogbw_from', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='w_mlogbw_from', to='wpm.mlogbw', verbose_name='来自单个产品'), + ), + migrations.AddField( + model_name='mlogbw', + name='mlogbw_to', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='w_mlogbw_to', to='wpm.mlogbw', verbose_name='指向单个产品'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index b0f1f24b..4232be25 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -436,6 +436,8 @@ 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") 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 a300ca2e..9c0ef4e4 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -732,7 +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"] + fields = ["id", "number", "wpr", "note", "mlogb", "ftest", "equip", "work_start_time", "work_end_time", "mlogb_to"] + read_only_fields = ["mlogb_to"] def validate(self, attrs): mlogb:Mlogb = attrs["mlogb"] diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 46ab47a9..9eecf7c2 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -586,6 +586,7 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust "material_out": material_out, } m_dict['batch'] = generate_new_batch(mlogbin.batch, mlog) + wm_in: WMaterial = mlogbin.wm_in if material_in.tracking == Material.MA_TRACKING_SINGLE: @@ -602,29 +603,41 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust 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}) - mlogbin.mlogb_to = mlogbout - mlogbin.save(update_fields = ["mlogb_to"]) + if mlogbin.mlogb_to is None: + mlogbin.mlogb_to = mlogbout + mlogbin.save(update_fields = ["mlogb_to"]) + elif mlogbin.mlogb_to != mlogbout: + raise ParseError("生成产出出错1") elif mtype == Process.PRO_DIV: for mlogbwin in Mlogbw.objects.filter(mlogb=mlogbin).order_by("number"): 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}) - mlogbwin.mlogb_to = mlogbout - mlogbwin.save(update_fields = ["mlogb_to"]) + if mlogbwin.mlogb_to is None: + mlogbwin.mlogb_to = mlogbout + mlogbwin.save(update_fields = ["mlogb_to"]) + elif mlogbwin.mlogb_to != mlogbout: + raise ParseError("生成产出出错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}) - mlogbin.mlogb_to = mlogbout - mlogbin.save(update_fields = ["mlogb_to"]) + if mlogbin.mlogb_to is None: + mlogbin.mlogb_to = mlogbout + mlogbin.save(update_fields = ["mlogb_to"]) + elif mlogbin.mlogb_to != mlogbout: + 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}) - mlogbin.mlogb_to = mlogbout - mlogbin.save(update_fields = ["mlogb_to"]) + if mlogbin.mlogb_to is None: + mlogbin.mlogb_to = mlogbout + mlogbin.save(update_fields = ["mlogb_to"]) + elif mlogbin.mlogb_to != mlogbout: + raise ParseError("生成产出出错4") else: raise ParseError("不支持生成产出物料!") @@ -632,12 +645,22 @@ 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: - Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbout, defaults={"number": wpr.number}) + 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: + 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}') + Mlogbw.objects.get_or_create(mlogb=mlogbout, number=f'{wpr.number}-{i+1}', defaults={"mlogbw_from": mlogbwin}) elif is_fix: - Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbout, defaults={"number": wpr.number}) + 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: + raise ParseError("生成产出出错6") else: raise ParseError("不支持的生产类型1") @@ -731,14 +754,19 @@ class MlogbwViewSet(CustomModelViewSet): ins.save(update_fields=["mlogb_to"]) if material_out.tracking == Material.MA_TRACKING_SINGLE: for i in range(div_number): - Mlogbw.objects.get_or_create(mlogb=mlogbout, defaults=f'{ins.number}-{i+1}') - Mlogbw.cal_count_notok(mlogbout) + 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: - Mlogbw.objects.get_or_create(mlogb=mlogb_to, wpr=ins.wpr, defaults={"number": ins.number}) + 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}') + Mlogbw.objects.get_or_create(mlogb=mlogb_to, number=f'{ins.number}-{i+1}', defaults={"mlogbw_from": ins}) Mlogbw.cal_count_notok(mlogb_to) @transaction.atomic @@ -759,17 +787,9 @@ class MlogbwViewSet(CustomModelViewSet): # 如果是输入且输出追踪到个,需同步删除 material_in: Material = mlogb.material_in if material_in is not None: - mlogb_to = mlogb.mlogb_to - material_out: Material = mlogb.mlog.material_out - route:Route = mlogb.mlog.route - mtype = route.process.mtype if route.process else None - if material_in.tracking == Material.MA_TRACKING_SINGLE and mtype == Process.PRO_DIV: - mlogbout_qs = Mlogb.objects.filter(id__in=list(Mlogbw.objects.filter(mlogb=mlogb).values_list("mlogb_to__id", flat=True))) - Ftest.objects.filter(id__in=Mlogbw.objects.filter(mlogb__in=mlogbout_qs).values_list('ftest__id', flat=True)).delete() - mlogbout_qs.delete() - Mlogbw.cal_count_notok(mlogb) - elif mlogb_to and material_out.tracking == Material.MA_TRACKING_SINGLE: - mbws = Mlogbw.objects.filter(Q(wpr=instance.wpr)|Q(number__contains=instance.number), mlogb=mlogb_to) - Ftest.objects.filter(id__in=mbws.values_list('ftest__id', flat=True)).delete() - mbws.delete() + if instance.mlogb_to: + Mlogb.objects.filter(id=instance.mlogb_to.id).delete() + if instance.mlogbw_to: + instance.mlogbw_to.delete() + instance.delete() Mlogbw.cal_count_notok(mlogb)