diff --git a/apps/wpm/migrations/0119_mlogb_route.py b/apps/wpm/migrations/0119_mlogb_route.py new file mode 100644 index 00000000..e8daf830 --- /dev/null +++ b/apps/wpm/migrations/0119_mlogb_route.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.12 on 2025-06-30 08:16 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0059_material_bin_number_main'), + ('wpm', '0118_batchst_mioitem'), + ] + + operations = [ + migrations.AddField( + model_name='mlogb', + name='route', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.route', verbose_name='生产步骤'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 86344831..3f10db98 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -368,7 +368,7 @@ class Mlogb(BaseModel): batch = models.TextField('批次号', null=True, blank=True, db_index=True) mtask = models.ForeignKey(Mtask, verbose_name='关联任务', on_delete=models.CASCADE, related_name='mlogb_mtask', null=True, blank=True) - + route = models.ForeignKey(Route, verbose_name='生产步骤', on_delete=models.SET_NULL, null=True, blank=True) wm_in = models.ForeignKey(WMaterial, verbose_name='投入物料所在库存', on_delete=models.SET_NULL, null=True, blank=True) material_in = models.ForeignKey( diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index c0928944..a2f9f501 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -378,6 +378,7 @@ class MlogSerializer(CustomModelSerializer): add_dict = { 'mlog': instance, 'batch': batch_in, 'wm_in': wm_in, 'mtask': instance.mtask, 'material_in': instance.material_in, + 'route': instance.route, 'count_use': instance.count_use, 'count_break': instance.count_break, 'count_pn_jgqbl': instance.count_pn_jgqbl } @@ -402,7 +403,8 @@ class MlogSerializer(CustomModelSerializer): if item['material_out'].id in brotherId_should_list: mlogbx = Mlogb.objects.create( mlog=instance, - batch=instance.batch, + batch=instance.batch, + route=instance.route, mtask=instance.mtask, material_out=item['material_out'], count_ok=item['count_ok']) @@ -423,7 +425,7 @@ class MlogSerializer(CustomModelSerializer): add_dict_2 = { 'mlog': instance, 'batch': batch_out, 'mtask': instance.mtask, 'material_out': instance.material_out, - 'count_real': instance.count_real, + 'count_real': instance.count_real, 'route': instance.route, 'count_ok': instance.count_ok, 'count_notok': instance.count_notok, 'count_break_t': instance.count_break_t, 'qct': instance.qct @@ -657,13 +659,14 @@ class MlogInitSerializer(CustomModelSerializer): attrs['material_out'] = None else: route: Route = attrs.get('route', None) - if not route: - raise ParseError('缺少工艺路线') - if route and route.process != mgroup.process: - raise ParseError('工序不匹配') - attrs['hour_work'] = route.hour_work - attrs['material_in'] = route.material_in - attrs['material_out'] = route.material_out + # if not route: + # raise ParseError('缺少工艺路线') + if route: + if route and route.process != mgroup.process: + raise ParseError('工序不匹配') + attrs['hour_work'] = route.hour_work + attrs['material_in'] = route.material_in + attrs['material_out'] = route.material_out attrs['fill_way'] = Mlog.MLOG_23 if attrs['mtype'] == Mlog.MTYPE_OUT: supplier = attrs.get('supplier', None) @@ -671,7 +674,8 @@ class MlogInitSerializer(CustomModelSerializer): raise ParseError('外协必须选择外协单位') if attrs.get('work_end_time', None): attrs['handle_date'] = localdate(attrs['work_end_time']) - if attrs["material_out"]: + # 如果已经确定产出,则自动获取qct + if attrs.get("material_out", None): attrs["qct"] = Qct.get(attrs["material_out"], "process") return attrs @@ -703,7 +707,7 @@ class MlogbInSerializer(CustomModelSerializer): class Meta: model = Mlogb - fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_pn_jgqbl', + fields = ['id', 'mlog', 'mtask', 'route', 'wm_in', 'count_use', 'count_pn_jgqbl', 'count_break', 'note', "parent", "mlogbdefect", "count_json_from"] extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': False}, 'wm_in': {'required': True, "allow_empty": False}} @@ -726,9 +730,19 @@ class MlogbInSerializer(CustomModelSerializer): raise ParseError('返修或复检需使用返修品/不合格品') elif wm_in.state != WMaterial.WM_OK: raise ParseError('非合格品不可使用') - if mtask and mlog.route != mtask.route: - raise ParseError('工序不匹配') - route = mlog.route + + mlog_route = mlog.route + if mlog_route is None: + if is_fix is False: + route = attrs.get("route", None) + if not route: + raise ParseError("缺少工艺步骤") + else: + route = mlog_route + attrs["route"] = route + + if mtask and route != mtask.route: + raise ParseError('工艺步骤与任务不匹配') attrs['material_in'] = wm_in.material attrs['batch'] = wm_in.batch attrs["batch_ofrom"] = wm_in.batch_ofrom diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 83123d2e..4e58d5ea 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -586,15 +586,18 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust def perform_create(self, serializer): mlogbin: Mlogb = serializer.save() mlog:Mlog = mlogbin.mlog - route:Route = mlog.route - process: Process = route.process if route else None - mtype = route.process.mtype if route else None + mgroup:Mgroup = mlog.mgroup + route:Route = mlogbin.route is_fix = mlog.is_fix - qct = mlog.qct + if route is None and is_fix is False: + raise ParseError('消耗物料缺失工艺步骤') + process: Process = mgroup.process if route else None + mtype = process.mtype if process else None + # qct = mlog.qct # 以及mlogbw material_in:Material = mlogbin.material_in # 如果是返修,则输出和输入相同 - material_out:Material = mlog.material_out if is_fix is False else material_in + material_out:Material = material_in if is_fix else route.material_out if material_out is None: raise ParseError('产物不可为空') # 如果是主要输入物料且是主批次,才需生成输出 @@ -608,24 +611,33 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust for wpr in Wpr.objects.filter(wm=wm_in).order_by("number"): Mlogbw.objects.get_or_create(wpr=wpr, mlogb=mlogbin, defaults={"number": wpr.number}) - if qct is None: - mlog.qct = Qct.get(material_out, "process") - mlog.save(update_fields = ["qct"]) + # if qct is None: + # mlog.qct = Qct.get(material_out, "process") + # mlog.save(update_fields = ["qct"]) m_dict = { "mtask": mlogbin.mtask, + "route": route, "mlog": mlog, "material_out": material_out, "batch": mlogbin.batch, "batch_ofrom": wm_in.batch_ofrom, "material_ofrom": wm_in.material_ofrom, - "qct": qct + "qct": Qct.get(material_out, "process") } if mtype == Process.PRO_DIV and material_in.tracking == Material.MA_TRACKING_SINGLE: pass else: m_dict['batch'] = generate_new_batch(mlogbin.batch, mlog) - if mtype == Process.PRO_NORMAL: # 正常 支持批到批, 个到个 + if is_fix:# 支持批到批,个到个 + d_count_real = mlogbin.count_use-mlogbin.count_pn_jgqbl + d_count_ok = d_count_real + mlogbout, _ = Mlogb.objects.get_or_create(mlogb_from=mlogbin, defaults=update_dict(m_dict,{"count_real": d_count_real, "count_ok": d_count_ok, "count_ok_full": d_count_ok})) + if material_in.tracking == Material.MA_TRACKING_SINGLE and material_out.tracking == Material.MA_TRACKING_SINGLE: + for mlogbwin in Mlogbw.objects.filter(mlogb=mlogbin).order_by("number"): + wpr_ = mlogbwin.wpr + Mlogbw.objects.get_or_create(wpr=wpr_, mlogb=mlogbout, defaults={"number": wpr_.number, "mlogbw_from": mlogbwin}) + elif mtype == Process.PRO_NORMAL: # 正常 支持批到批, 个到个 d_count_real = mlogbin.count_use - mlogbin.count_pn_jgqbl d_count_ok = d_count_real mlogbout, _ = Mlogb.objects.get_or_create(mlogb_from=mlogbin, defaults= @@ -701,14 +713,6 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust else: numberx = f'{number}-{i+1}' Mlogbw.objects.get_or_create(number=numberx, mlogb=mlogbout) - elif is_fix:# 支持批到批,个到个 - d_count_real = mlogbin.count_use-mlogbin.count_pn_jgqbl - d_count_ok = d_count_real - mlogbout, _ = Mlogb.objects.get_or_create(mlogb_from=mlogbin, defaults=update_dict(m_dict,{"count_real": d_count_real, "count_ok": d_count_ok, "count_ok_full": d_count_ok})) - if material_in.tracking == Material.MA_TRACKING_SINGLE and material_out.tracking == Material.MA_TRACKING_SINGLE: - for mlogbwin in Mlogbw.objects.filter(mlogb=mlogbin).order_by("number"): - wpr_ = mlogbwin.wpr - Mlogbw.objects.get_or_create(wpr=wpr_, mlogb=mlogbout, defaults={"number": wpr_.number, "mlogbw_from": mlogbwin}) else: raise ParseError("不支持生成产出物料!") mlog.cal_mlog_count_from_mlogb()