From 439bfeb7d6d4fb80afa4583ef3c791598ec14a84 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 25 Apr 2025 11:27:14 +0800 Subject: [PATCH 1/8] =?UTF-8?q?fix:=20=E8=BF=94=E5=B7=A5=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E7=89=A9=E6=96=99=E9=80=89=E6=8B=A9=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 2 ++ apps/wpm/views.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index bfa31f78..dc209f6b 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -703,6 +703,8 @@ class MlogbInSerializer(CustomModelSerializer): raise ParseError("请选择相应车间库存!") if is_fix: # 返修或复检 if wm_in.state in [WMaterial.WM_REPAIR, WMaterial.WM_NOTOK]: + pass + else: raise ParseError('返修或复检需使用返修品/不合格品') elif wm_in.state != WMaterial.WM_OK: raise ParseError('非合格品不可使用') diff --git a/apps/wpm/views.py b/apps/wpm/views.py index e3525e24..2abd9cbb 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -583,7 +583,7 @@ 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 and not (is_fix and mtype == Process.PRO_PROD): + if qct is None: mlog.qct = Qct.get(material_out, "process") mlog.save(update_fields = ["qct"]) From 000ea6fc27a3488755026ee4423391f17017e9ea Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 25 Apr 2025 13:20:16 +0800 Subject: [PATCH 2/8] =?UTF-8?q?fix:=20=E7=94=9F=E4=BA=A7=E5=85=A5=E5=BA=93?= =?UTF-8?q?=E6=97=B6=E5=AD=98=E5=85=A5=E7=94=9F=E4=BA=A7=E8=BD=A6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/inm/services.py b/apps/inm/services.py index edcdb208..f424aeab 100644 --- a/apps/inm/services.py +++ b/apps/inm/services.py @@ -169,7 +169,7 @@ def do_in(item: MIOItem): else: raise ParseError(f'{str(xmaterial)}-{xbatch}车间物料不足') - wm_production_dept = wm.mgroup.belong_dept if wm.mgroup else None + wm_production_dept = wm.mgroup.belong_dept if wm.mgroup else wm.belong_dept if production_dept is None: production_dept = wm_production_dept elif wm_production_dept and production_dept != wm_production_dept: From 6033216869a444eb296a5bb00f9a8155f423e815 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 25 Apr 2025 14:21:24 +0800 Subject: [PATCH 3/8] =?UTF-8?q?fix:=20mloginit=E5=9C=A8=E8=BF=94=E5=B7=A5?= =?UTF-8?q?=E6=97=B6=E4=B8=8D=E6=8E=A5=E6=94=B6route?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index dc209f6b..ddb134cb 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -628,21 +628,20 @@ class MlogInitSerializer(CustomModelSerializer): } def validate(self, attrs): - route: Route = attrs.get('route', None) mgroup: Mgroup = attrs['mgroup'] is_fix:bool = attrs.get('is_fix', False) attrs['mtype'] = mgroup.mtype if is_fix: attrs["route"] = None - elif route is None: - raise ParseError('缺少工艺路线') - if route and route.process != mgroup.process: - raise ParseError('工序不匹配') - if is_fix: attrs['hour_work'] = None attrs['material_in'] = None attrs['material_out'] = None - if route: + 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 From d6fe5af39cee1370a378fda21c3744b3e42a3eb3 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 25 Apr 2025 15:24:38 +0800 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=E5=8D=95=E5=A1=AB=E5=86=99mlog?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=BF=94=E5=B7=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 43 ++++++++++++++++++++++++++--------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index ddb134cb..8edd22c3 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -359,6 +359,9 @@ class MlogSerializer(CustomModelSerializer): with transaction.atomic(): mlogb = validated_data.pop('mlogb', []) instance: Mlog = super().create(validated_data) + ## 返工没有加工前不良 + if instance.is_fix and instance.count_pn_jgqbl >0: + raise ParseError("返工不支持加工前不良") # 自动生成mlogb batch_in = instance.batch wm_in = instance.wm_in @@ -457,6 +460,9 @@ class MlogSerializer(CustomModelSerializer): with transaction.atomic(): mlogb = validated_data.pop('mlogb', []) instance: Mlog = super().update(instance, validated_data) + ## 返工没有加工前不良 + if instance.is_fix and instance.count_pn_jgqbl >0: + raise ParseError("返工不支持加工前不良") wm_in = instance.wm_in batch_in = instance.batch if wm_in: @@ -541,33 +547,37 @@ class MlogSerializer(CustomModelSerializer): attrs['mtype'] = Mlog.MTYPE_SELF # 默认为自生产 fmlog:Fmlog = attrs.get('fmlog', None) mtaskb = attrs.get('mtaskb', None) + wm_in: WMaterial = attrs.get('wm_in', None) if fmlog: attrs['fill_way'] = Mlog.MLOG_12 - wm_in: WMaterial = attrs.get('wm_in', None) - if wm_in: - pass - else: + if not wm_in: raise ParseError('未提供消耗的车间物料') attrs['mgroup'] = fmlog.mgroup + attrs['is_fix'] = fmlog.is_fix attrs['mtask'] = fmlog.mtask attrs['route'] = fmlog.route attrs['mtype'] = fmlog.mgroup.mtype if attrs['mtask'] and attrs['mtask'].route: attrs['route'] = attrs['mtask'].route - # if attrs['mtask'].mtaskb and mtaskb is None: - # raise ParseError('子任务不能为空') if mtaskb and mtaskb.mtask != fmlog.mtask: raise ParseError('子任务不一致') - if wm_in.state in [WMaterial.WM_OK]: - pass - else: + if wm_in: + attrs["material_in"] = wm_in.material + attrs["batch"] = wm_in.batch + if attrs["is_fix"]: + attrs["material_out"] = attrs["material_in"] + if wm_in.state in [WMaterial.WM_REPAIR, WMaterial.WM_NOTOK]: + pass + else: + raise ParseError('返修或复检需使用返修品/不合格品') + elif wm_in.state != WMaterial.WM_OK: raise ParseError('非合格品不可使用') - if wm_in.material != attrs['route'].material_in: + if attrs['route'] and wm_in.material != attrs['route'].material_in: raise ParseError('消耗物料与工艺步骤不一致') - if attrs['mtype'] == Mlog.MTYPE_OUT: - supplier = attrs.get('supplier', None) - if not supplier: - raise ParseError('外协必须选择外协单位') + if attrs['mtype'] == Mlog.MTYPE_OUT: + supplier = attrs.get('supplier', None) + if not supplier: + raise ParseError('外协必须选择外协单位') mtask = attrs.get('mtask', None) count_notok = 0 for i in attrs: @@ -588,8 +598,6 @@ class MlogSerializer(CustomModelSerializer): else: if attrs.get('work_end_time', None): attrs['handle_date'] = localdate(attrs['work_end_time']) - elif attrs.get('work_start_time', None): - attrs['handle_date'] = localdate(attrs['work_start_time']) mtaskb: Mtaskb = attrs.get('mtaskb', None) if mtaskb: mtask = mtaskb.mtask @@ -599,6 +607,8 @@ class MlogSerializer(CustomModelSerializer): attrs['mgroup'] = mtask.mgroup attrs['material_in'] = mtask.material_in material_out = mtask.material_out + if wm_in and wm_in.material != mtask.material_in: + raise ParseError('消耗物料与任务不一致') attrs['material_out'] = material_out if mtask.start_date == mtask.end_date: attrs['handle_date'] = mtask.end_date @@ -1223,6 +1233,7 @@ class FmlogSerializer(CustomModelSerializer): is_fix = attrs.get("is_fix", False) if is_fix: attrs["mtask"] = None + attrs['route'] = None elif not attrs.get("mtask", None) and not attrs.get("route", None): raise ParseError("请选择任务或工艺步骤") mtask: Mtask = attrs['mtask'] From be57fec29f441e1d3c7622ef4af4a5b96692b47d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 25 Apr 2025 16:27:48 +0800 Subject: [PATCH 5/8] =?UTF-8?q?fix:=20=E8=8E=B7=E5=8F=96batchst=E6=97=B6?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E4=BD=BF=E7=94=A8version=3D1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 77d68057..486be373 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -621,7 +621,7 @@ class BatchSt(BaseModel): 创建新的批次 """ if mio is None and handover is None and mlog is None: - return cls.objects.get_or_create(batch=batch) + return cls.objects.get_or_create(batch=batch, version=1) else: version = 1 # 带有来源的批次获取,需检查批次号是否可用 From c8d05bed680b0ba347286522d3e066753556f78a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 25 Apr 2025 21:35:37 +0800 Subject: [PATCH 6/8] =?UTF-8?q?feat:=20=E8=8E=B7=E5=8F=96=E8=AF=A5?= =?UTF-8?q?=E6=89=B9=E6=AC=A1=E7=9A=84dag=E6=95=B0=E6=8D=AE=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E4=BC=A0=E5=85=A5version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 4 ++-- apps/wpm/views.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index c1061103..825fb63d 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -961,9 +961,9 @@ def mlog_audit_end(ticket: Ticket): mlog_submit(ins, ticket.create_by, now) -def get_batch_dag(batch_number: str): +def get_batch_dag(batch_number: str, version=1): try: - batch_ins = BatchSt.objects.get(batch=batch_number) + batch_ins = BatchSt.objects.get(batch=batch_number, version=version) except Exception: raise ParseError("该批次号未构建关系链") # 收集所有相关批次和边 diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 2abd9cbb..653bab38 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -816,6 +816,7 @@ class BatchLogViewSet(ListModelMixin, CustomGenericViewSet): 获取该批次的DAG图数据 """ batch = request.data.get("batch", None) + version = request.data.get("version", 1) if not batch: raise ParseError("缺少batch参数") - return Response(get_batch_dag(batch)) \ No newline at end of file + return Response(get_batch_dag(batch, version)) \ No newline at end of file From cdb9083def8289cd5f6a157aa65bd4961d6489f6 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 25 Apr 2025 23:41:59 +0800 Subject: [PATCH 7/8] =?UTF-8?q?fix:=20batchst=E6=81=A2=E5=A4=8D=E6=88=90ba?= =?UTF-8?q?tch=E5=8D=95=E4=B8=80=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/services.py | 12 ++++-------- apps/wpm/models.py | 24 +++++++++++++++++++----- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/inm/services.py b/apps/inm/services.py index f424aeab..f7617c04 100644 --- a/apps/inm/services.py +++ b/apps/inm/services.py @@ -247,10 +247,8 @@ class InmService: BatchLog.clear(mio=instance) else: for item in MIOItem.objects.filter(mio=instance): - if item.mb: # 说明录入到已有批次 - BatchSt.g_create(batch=item.batch) - else: - BatchSt.g_create(batch=item.batch, mio=instance, material_start=item.material) + BatchSt.g_create( + batch=item.batch, mio=instance, material_start=item.material, reuse_node=True) from apps.pum.services import PumService if is_reverse: cls.update_mb(instance, -1) @@ -262,10 +260,8 @@ class InmService: BatchLog.clear(mio=instance) else: for item in MIOItem.objects.filter(mio=instance): - if item.mb: - BatchSt.g_create(batch=item.batch) - else: - BatchSt.g_create(batch=item.batch, mio=instance, material_start=item.material) + BatchSt.g_create( + batch=item.batch, mio=instance, material_start=item.material, reuse_node=True) if is_reverse: cls.update_mb(instance, -1) else: diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 486be373..c0e39396 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -616,18 +616,32 @@ class BatchSt(BaseModel): unique_together = [("batch", "version")] @classmethod - def g_create(cls, batch:str, mio=None, handover=None, mlog=None, material_start=None): + def g_create(cls, batch:str, mio=None, handover=None, mlog=None, material_start=None, reuse_node=False): """ 创建新的批次 """ if mio is None and handover is None and mlog is None: - return cls.objects.get_or_create(batch=batch, version=1) + try: + node = cls.objects.get(batch=batch) + except cls.DoesNotExist: + return cls.objects.create(batch=batch), True + except cls.MultipleObjectsReturned: + # 兼容性处理 + node = cls.objects.filter(batch=batch).order_by('-version').first() + return node, False else: version = 1 # 带有来源的批次获取,需检查批次号是否可用 - if cls.objects.filter(batch=batch, version=1).exists(): - latest_version = BatchSt.objects.filter(batch=batch).aggregate(Max("version"))["version__max"] - version = latest_version + 1 + if cls.objects.filter(batch=batch).exists(): + if reuse_node: + node = cls.objects.filter(batch=batch).order_by('-version').first() + if node.material_start is not None and node.material_start != material_start: + raise ParseError(f"{batch}-该批次号因物料不同不可引用") + return node, False + else: + raise ParseError(f"{batch}-该批次号不可使用") + # latest_version = BatchSt.objects.filter(batch=batch).aggregate(Max("version"))["version__max"] + # version = latest_version + 1 if mio is None and handover is None and mlog is None: raise ParseError("mio or handover or mlog must be provided") ins = cls.objects.create(batch=batch, mio=mio, handover=handover, mlog=mlog, material_start=material_start, version=version) From 139aa6de27dd8f925e9f99cd710cdbed962d5d7f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sat, 26 Apr 2025 00:07:44 +0800 Subject: [PATCH 8/8] =?UTF-8?q?feat:=20wmaterial=E7=AD=9B=E9=80=89?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E4=BC=98=E5=8C=96=E6=9D=A5=E6=96=99=E5=B7=B2?= =?UTF-8?q?=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index bd0d04bf..a4a17fc4 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -53,7 +53,7 @@ class WMaterialFilter(filters.FilterSet): qs = queryset.exclude(material__id__in=matoutIds)|queryset.filter(state=WMaterial.WM_REPAIR) return qs elif value == "done": - qs = queryset.filter(material__id__in=matoutIds)|queryset.filter(state=WMaterial.WM_REPAIRED) + qs = queryset.filter(material__id__in=matoutIds).exclude(state=WMaterial.WM_REPAIR)|queryset.filter(state=WMaterial.WM_REPAIRED) return qs else: raise ParseError("请提供工段查询条件")