diff --git a/apps/qm/migrations/0047_ftestwork_count_ok_full.py b/apps/qm/migrations/0047_ftestwork_count_ok_full.py new file mode 100644 index 00000000..e3ce222d --- /dev/null +++ b/apps/qm/migrations/0047_ftestwork_count_ok_full.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2025-03-04 07:06 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0046_alter_testitem_description'), + ] + + operations = [ + migrations.AddField( + model_name='ftestwork', + name='count_ok_full', + field=models.PositiveIntegerField(blank=True, null=True, verbose_name='完全合格数量'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index b10422df..dc0c3458 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -235,6 +235,7 @@ class FtestWork(CommonBDModel): count_sampling = models.PositiveIntegerField('抽检数量', default=0) count_sampling_ok = models.PositiveIntegerField('抽检合格数量', default=0) count_ok = models.PositiveIntegerField('合格数量', default=0) + count_ok_full = models.PositiveIntegerField('完全合格数量', null=True, blank=True) count_notok = models.PositiveIntegerField('不合格数量', default=0) need_update_wm = models.BooleanField('是否更新车间库存', default=True) count_notok_json = models.JSONField('不合格项数量统计', default=dict, null=False, blank=True) @@ -260,7 +261,10 @@ class FtestWork(CommonBDModel): def cal_count(self): self.count_notok = FtestworkDefect.objects.filter( ftestwork=self, defect__okcate=30).aggregate(total=Sum("count"))["total"] or 0 + count_notok_full = FtestworkDefect.objects.filter( + ftestwork=self).exclude(defect__okcate=10).aggregate(total=Sum("count"))["total"] or 0 self.count_ok = self.count - self.count_notok + self.count_ok_full = self.count - count_notok_full if self.type2 == 20: #全检 self.count_sampling = self.count self.count_sampling_ok = self.count_ok diff --git a/apps/qm/services.py b/apps/qm/services.py index babdfca6..3a390340 100644 --- a/apps/qm/services.py +++ b/apps/qm/services.py @@ -102,16 +102,20 @@ def ftestwork_submit(ins:FtestWork, user: User): # 此时调用了qct表 for item in FtestworkDefect.objects.filter(ftestwork=ins): item:FtestworkDefect = item - if item.count > 0 and item.defect.okcate == Defect.DEFECT_NOTOK: + if item.count > 0: wm.count = wm.count - item.count if wm.count < 0: raise ParseError("数量不足,扣减失败") + wm.save() + wmstate = WMaterial.WM_OK + if item.defect.okcate == Defect.DEFECT_NOTOK: + wmstate = WMaterial.WM_NOTOK wmx, new_create = WMaterial.objects.get_or_create( material=wm.material, batch=wm.batch, mgroup=wm.mgroup, belong_dept=wm.belong_dept, - state=WMaterial.WM_NOTOK, + state=wmstate, notok_sign=None, defect=item.defect, defaults={ @@ -121,7 +125,6 @@ def ftestwork_submit(ins:FtestWork, user: User): if not new_create: wmx.count = wmx.count + item.count wmx.save() - wm.save() ins.submit_user = user ins.submit_time = timezone.now() ins.save() diff --git a/apps/wpm/migrations/0092_auto_20250304_1433.py b/apps/wpm/migrations/0092_auto_20250304_1433.py new file mode 100644 index 00000000..f23aea30 --- /dev/null +++ b/apps/wpm/migrations/0092_auto_20250304_1433.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.12 on 2025-03-04 06:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0091_auto_20250303_1708'), + ] + + operations = [ + migrations.AddField( + model_name='mlog', + name='count_ok_full', + field=models.PositiveIntegerField(blank=True, null=True, verbose_name='完全合格数'), + ), + migrations.AddField( + model_name='mlogb', + name='count_ok_full', + field=models.PositiveIntegerField(blank=True, null=True, verbose_name='完全合格数'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index ac409394..a55a8997 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -207,6 +207,7 @@ class Mlog(CommonADModel): count_break = models.PositiveIntegerField('加工碎料数', default=0) count_ok = models.PositiveIntegerField('合格数', default=0) + count_ok_full = models.PositiveIntegerField('完全合格数', null=True, blank=True) count_notok = models.PositiveIntegerField('不合格数', default=0) count_break_t = models.PositiveIntegerField('检验碎料数', default=0) @@ -294,12 +295,6 @@ class Mlog(CommonADModel): def mlogdefect(self): return MlogbDefect.objects.filter(mlogb__mlog=self) - def cal_count_notok(self): - count_notok = MlogbDefect.objects.filter(defect__okcate=30, mlogb__mlog=self).aggregate(total=Sum("count"))["total"] or 0 - self.count_notok = count_notok - self.count_ok = self.count_real - count_notok - self.save(update_fields=["count_ok", "count_notok"]) - @classmethod def count_fields(cls): mlog_count_fields = [] @@ -344,6 +339,7 @@ class Mlogb(BaseModel): count_break_t = models.PositiveIntegerField('检验碎料数', default=0) count_real = models.PositiveIntegerField('实际生产数', default=0) count_ok = models.PositiveIntegerField('合格数量', default=0) + count_ok_full = models.PositiveIntegerField('完全合格数', null=True, blank=True) count_notok = models.PositiveIntegerField('不合格数', default=0) count_pn_jgqbl = models.PositiveIntegerField('加工前不良', default=0) @@ -376,9 +372,19 @@ class Mlogb(BaseModel): def cal_count_notok(self): count_notok = MlogbDefect.objects.filter(defect__okcate=30, mlogb=self).aggregate(total=Sum("count"))["total"] or 0 + count_notok_full = MlogbDefect.objects.filter(mlogb=self).exclude(defect__okcate=10).aggregate(total=Sum("count"))["total"] or 0 self.count_notok = count_notok self.count_ok = self.count_real - count_notok - self.save(update_fields=["count_ok", "count_notok"]) + self.count_ok_full = self.count_real - count_notok_full + self.save(update_fields=["count_ok", "count_notok", "count_ok_full"]) + mlog = self.mlog + if mlog: + count_notok = MlogbDefect.objects.filter(defect__okcate=30, mlogb__mlog=mlog).aggregate(total=Sum("count"))["total"] or 0 + count_notok_full = MlogbDefect.objects.filter(mlogb__mlog=mlog).exclude(defect__okcate=10).aggregate(total=Sum("count"))["total"] or 0 + mlog.count_ok_full = self.count_real - count_notok_full + mlog.count_notok = count_notok + mlog.count_ok = self.count_real - count_notok + mlog.save(update_fields=["count_ok", "count_notok", "count_ok_full"]) class MlogbDefect(BaseModel): mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 8cfd02e5..eb642089 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -394,7 +394,8 @@ class MlogSerializer(CustomModelSerializer): 'mtask': instance.mtask, 'material_out': instance.material_out, 'count_real': instance.count_real, 'count_ok': instance.count_ok, 'count_notok': instance.count_notok, - 'count_break_t': instance.count_break_t + 'count_break_t': instance.count_break_t, + 'qct': instance.qct } need_mdfect = False if instance.qct or mlogdefect: @@ -414,7 +415,7 @@ class MlogSerializer(CustomModelSerializer): ] if mlogb_defect_objects: MlogbDefect.objects.bulk_create(mlogb_defect_objects) - instance.cal_count_notok() + mlogb.cal_count_notok() return instance def update(self, instance, validated_data): @@ -450,6 +451,7 @@ class MlogSerializer(CustomModelSerializer): minx.count_use = instance.count_use minx.count_break = instance.count_break minx.count_pn_jgqbl = instance.count_pn_jgqbl + minx.qct = instance.qct minx.save() Mlogb.objects.filter(mlog=instance, material_in__isnull=False).exclude(id=minx.id).delete() @@ -496,7 +498,7 @@ class MlogSerializer(CustomModelSerializer): ] if mlogb_defect_objects: MlogbDefect.objects.bulk_create(mlogb_defect_objects) - instance.cal_count_notok() + mox.cal_count_notok() return instance def validate(self, attrs): @@ -904,7 +906,7 @@ class HandoverSerializer(CustomModelSerializer): # raise ParseError(f'第{ind+1}物料与交接部门不一致') if attrs["material"] != wm.material: raise ParseError(f'第{ind+1}物料与交接物料不一致') - if (wm.notok_sign or wm.defect) and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]: + if wm.state != WMaterial.WM_OK and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]: raise ParseError(f'第{ind+1}物料不合格,不能进行正常/检验交接') if wm.count_xtest is not None: raise ParseError(f'第{ind+1}物料检验中,不能进行交接') diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 60a15adf..8ac20a0c 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -237,13 +237,12 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): stored_notok = need_store_notok stored_mgroup = need_store_notok if mlogb_out_qs.exists(): - m_outs_list = [(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight, None, mo) for mo in mlogb_out_qs.all()] + m_outs_list = [(mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok_full if mo.count_ok_full is not None else mo.count_ok, mlog.count_real_eweight, None, mo) for mo in mlogb_out_qs.all()] if need_store_notok: for item in mlogb_out_qs: - if item.qct is not None: - if MlogbDefect.objects.filter(mlogb=item).exists(): - pass - elif item.material_out.tracking == Material.MA_TRACKING_SINGLE: + mbd_qs = MlogbDefect.objects.filter(mlogb=item) + if item.qct is not None or mbd_qs.exists(): + if item.material_out.tracking == Material.MA_TRACKING_SINGLE: Mlogbw.cal_count_notok(item) for itemx in MlogbDefect.objects.filter(mlogb=item): m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item)) @@ -281,9 +280,13 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): if process.type == Process.PRO_PROD: wm_state = WMaterial.WM_REPAIRED # 返修只有返修完成品 elif process.type == Process.PRO_TEST: - wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK + wm_state = WMaterial.WM_OK if notok_sign_or_defect is None or ( + isinstance(notok_sign_or_defect, Defect) and notok_sign_or_defect.okcate in [Defect.DEFECT_OK, Defect.DEFECT_OK_B] + ) else WMaterial.WM_NOTOK else: - wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK + wm_state = WMaterial.WM_OK if notok_sign_or_defect is None or ( + isinstance(notok_sign_or_defect, Defect) and notok_sign_or_defect.okcate in [Defect.DEFECT_OK, Defect.DEFECT_OK_B] + ) else WMaterial.WM_NOTOK lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None, 'notok_sign': None, 'defect': None, 'state': wm_state} if isinstance(notok_sign_or_defect, Defect): @@ -367,14 +370,13 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): mlogb_out_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) if mlogb_out_qs.exists(): m_outs_list = [ - (mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok, mlog.count_real_eweight, None, mo) + (mo.material_out, mo.batch if mo.batch else mlog.batch, mo.count_ok_full if mo.count_ok_full is not None else mo.count_ok, mlog.count_real_eweight, None, mo) for mo in mlogb_out_qs.all()] if stored_notok: for item in mlogb_out_qs: - if item.qct is not None: - if MlogbDefect.objects.filter(mlogb=item).exists(): - pass - elif item.material_out.tracking == Material.MA_TRACKING_SINGLE: + mbd_qs = MlogbDefect.objects.filter(mlogb=item) + if item.qct is not None or mbd_qs.exists(): + if item.material_out.tracking == Material.MA_TRACKING_SINGLE: Mlogbw.cal_count_notok(item) for itemx in MlogbDefect.objects.filter(mlogb=item): m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item)) @@ -412,9 +414,13 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): if process.type == Process.PRO_PROD: wm_state = WMaterial.WM_REPAIRED else: # 检验工序正常生成 - wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK + wm_state = WMaterial.WM_OK if notok_sign_or_defect is None or ( + isinstance(notok_sign_or_defect, Defect) and notok_sign_or_defect.okcate in [Defect.DEFECT_OK, Defect.DEFECT_OK_B] + ) else WMaterial.WM_NOTOK else: - wm_state = WMaterial.WM_OK if notok_sign_or_defect is None else WMaterial.WM_NOTOK + wm_state = WMaterial.WM_OK if notok_sign_or_defect is None or ( + isinstance(notok_sign_or_defect, Defect) and notok_sign_or_defect.okcate in [Defect.DEFECT_OK, Defect.DEFECT_OK_B] + ) else WMaterial.WM_NOTOK lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None, 'notok_sign': None, 'defect': None, 'state': wm_state} if isinstance(notok_sign_or_defect, Defect): lookup['defect'] = notok_sign_or_defect diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 1111acb9..de8e883f 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -610,6 +610,9 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust pass elif mlogbout.qct is None: mlogbout.qct = Qct.get(mlogbout.material_out, "process") if mlog.qct is None else mlog.qct + if mlogbout.qct is not None and mlog.qct is None: + mlog.qct = mlogbout.qct + mlog.save(update_fields=["qct"]) mlogbout.count_real = d_count_real mlogbout.count_ok = d_count_ok mlogbout.save()