From 81561b523825c4ea372a60ae448be0b8c5ee6422 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 09:10:52 +0800 Subject: [PATCH 01/29] =?UTF-8?q?fix:=20MlogbInUpdateSerializer=20?= =?UTF-8?q?=E8=81=94=E5=8A=A8count=5Fuse=20=E5=92=8C=20count=5Freal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index bfe1df68..faf97ea4 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -824,10 +824,9 @@ class MlogbInUpdateSerializer(CustomModelSerializer): MlogbDefect.objects.bulk_create(mlogb_defect_objects) ins.cal_count_pn_jgqbl(cal_mlog=False) # 只有普通工序的才可联动 - material_out:Material = ins.mlog.material_out - route:Route = mlog.route - if material_out.tracking == Material.MA_TRACKING_BATCH: - if route and route.process and route.process.mtype == Process.PRO_NORMAL: + route:Route = ins.route if ins.route else ins.mlog.route + if route and route.process and route.process.mtype == Process.PRO_NORMAL: + if route.material_out.tracking == Material.MA_TRACKING_BATCH: mlogbout_qs = Mlogb.objects.filter(mlog=ins.mlog, mlogb_from=ins) if mlogbout_qs.count() == 1: mlogbout = mlogbout_qs.first() From 9af23216b6d5082faeddc6623a201c6f9bfa44f6 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 11:09:12 +0800 Subject: [PATCH 02/29] =?UTF-8?q?feat:=20MlogSerializer=20=E5=A4=84?= =?UTF-8?q?=E7=90=86=20work=5Fstart=5Ftime=20=E7=9A=84=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index faf97ea4..6a74d8a0 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -635,7 +635,7 @@ class MlogSerializer(CustomModelSerializer): mgroup:Mgroup = attrs['mgroup'] work_start_time:datetime = attrs['work_start_time'] handle_date, attrs["shift"] = mgroup.get_shift(work_start_time) - if mtask.start_date == mtask.end_date: + if mtask and mtask.start_date == mtask.end_date: attrs['handle_date'] = mtask.end_date if attrs['handle_date'] != handle_date: raise ParseError('任务日期与生产日期不一致') From c997cba6a58b42fd9a53fde167bfef936d536583 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 11:23:37 +0800 Subject: [PATCH 03/29] =?UTF-8?q?feat:=20route=E9=87=87=E7=94=A8=E5=BC=95?= =?UTF-8?q?=E7=94=A8=E6=96=B9=E5=BC=8F=E5=85=81=E8=AE=B8=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/filters.py | 3 +- .../mtm/migrations/0062_auto_20250902_1122.py | 24 +++++++++++++ apps/mtm/models.py | 3 +- apps/mtm/serializers.py | 36 +++++++++++++------ apps/mtm/views.py | 21 ++++++++--- 5 files changed, 69 insertions(+), 18 deletions(-) create mode 100644 apps/mtm/migrations/0062_auto_20250902_1122.py diff --git a/apps/mtm/filters.py b/apps/mtm/filters.py index 334e154f..52d45059 100644 --- a/apps/mtm/filters.py +++ b/apps/mtm/filters.py @@ -58,5 +58,6 @@ class RouteFilter(filters.FilterSet): "mgroup": ["exact", "in", "isnull"], "mgroup__name": ["exact", "contains"], "mgroup__belong_dept": ["exact"], - "mgroup__belong_dept__name": ["exact", "contains"] + "mgroup__belong_dept__name": ["exact", "contains"], + "from_route": ["exact", "isnull"], } diff --git a/apps/mtm/migrations/0062_auto_20250902_1122.py b/apps/mtm/migrations/0062_auto_20250902_1122.py new file mode 100644 index 00000000..1ab1057a --- /dev/null +++ b/apps/mtm/migrations/0062_auto_20250902_1122.py @@ -0,0 +1,24 @@ +# Generated by Django 3.2.12 on 2025-09-02 03:22 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0061_material_img'), + ] + + operations = [ + migrations.AddField( + model_name='route', + name='from_route', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='route_f', to='mtm.route', verbose_name='来源路线'), + ), + migrations.AlterField( + model_name='route', + name='parent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='route_parent', to='mtm.route', verbose_name='上级路线'), + ), + ] diff --git a/apps/mtm/models.py b/apps/mtm/models.py index d382d310..a4bb4b7f 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -415,8 +415,9 @@ class Route(CommonADModel): batch_bind = models.BooleanField('是否绑定批次', default=True) materials = models.ManyToManyField(Material, verbose_name='关联辅助物料', related_name="route_materials", through="mtm.routemat", blank=True) - parent = models.ForeignKey('self', verbose_name='上级路线', on_delete=models.CASCADE, null=True, blank=True) + parent = models.ForeignKey('self', verbose_name='上级路线', on_delete=models.CASCADE, null=True, blank=True, related_name="route_parent") params_json = models.JSONField('工艺参数', default=dict, blank=True) + from_route = models.ForeignKey('self', verbose_name='来源路线', on_delete=models.SET_NULL, null=True, blank=True, related_name="route_f") def __str__(self): x = "" diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index fed32f54..c3124339 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -247,7 +247,7 @@ class RouteSerializer(CustomModelSerializer): # if material and process and Route.objects.filter(material=material, process=process).exists(): # raise ValidationError('已选择该工序!!') with transaction.atomic(): - instance = super().create(validated_data) + instance:Route = super().create(validated_data) material_out = instance.material_out if material_out: if material_out.process is None: @@ -263,12 +263,16 @@ class RouteSerializer(CustomModelSerializer): if instance.material: instance.material_out = RouteSerializer.gen_material_out(instance, material_out_tracking, user=self.request.user) instance.save() - rx = Route.objects.filter(material_in=instance.material_in, material_out=instance.material_out, process=process).exclude(id=instance.id).first() + rx = Route.objects.filter( + material_in=instance.material_in, material_out=instance.material_out, + process=process).exclude(id=instance.id).order_by("create_time").first() if rx: - msg = "" - if rx.routepack: - msg = rx.routepack.name - raise ParseError(f"该工艺步骤已存在-{msg}") + instance.from_route = rx + instance.save() + # msg = "" + # if rx.routepack: + # msg = rx.routepack.name + # raise ParseError(f"该工艺步骤已存在-{msg}") return instance def update(self, instance, validated_data): @@ -294,12 +298,16 @@ class RouteSerializer(CustomModelSerializer): if instance.material: instance.material_out = RouteSerializer.gen_material_out(instance, material_out_tracking, user=self.request.user) instance.save() - rx = Route.objects.filter(material_in=instance.material_in, material_out=instance.material_out, process=process).exclude(id=instance.id).first() + rx = Route.objects.filter( + material_in=instance.material_in, material_out=instance.material_out, + process=process).exclude(id=instance.id).order_by("create_time").first() if rx: - msg = "" - if rx.routepack: - msg = rx.routepack.name - raise ParseError(f"该工艺步骤已存在-{msg}") + instance.from_route = rx + instance.save() + # msg = "" + # if rx.routepack: + # msg = rx.routepack.name + # raise ParseError(f"该工艺步骤已存在-{msg}") return instance def to_representation(self, instance): @@ -330,6 +338,12 @@ class RouteMatSerializer(CustomModelSerializer): model = RouteMat fields = "__all__" read_only_fields = EXCLUDE_FIELDS_BASE + + def validate(self, attrs): + route:Route = attrs["route"] + if route.from_route is not None: + raise ParseError("该工艺步骤引用其他步骤,无法修改") + return attrs class MaterialExportSerializer(CustomModelSerializer): diff --git a/apps/mtm/views.py b/apps/mtm/views.py index 1ad675d3..36508f4a 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -368,12 +368,23 @@ class RouteViewSet(CustomModelViewSet): select_related_fields = ['material', 'process', 'material_in', 'material_out', 'mgroup', 'routepack'] - def update(self, request, *args, **kwargs): - obj:Route = self.get_object() - routepack = obj.routepack + @transaction.atomic + def perform_update(self, serializer): + ins:Route = self.get_object() + if ins.from_route is not None: + raise ParseError('该工艺步骤引用其他步骤, 无法编辑') + old_m_in, old_m_out, process = ins.material_in, ins.material_out, ins.process + routepack = ins.routepack if routepack and routepack.state != RoutePack.RP_S_CREATE: - raise ParseError('该状态下不可编辑') - return super().update(request, *args, **kwargs) + raise ParseError('该工艺路线非创建中不可编辑') + ins_n:Route = serializer.save() + if ins_n.material_in != old_m_in or ins_n.material_out != old_m_out or ins_n.process != process: + raise ParseError("该工艺步骤被其他步骤引用, 无法修改关键信息") + + def perform_destroy(self, instance:Route): + if Route.objects.filter(from_route=instance).exists(): + raise ParseError('该工艺步骤被其他步骤引用,无法删除') + return super().perform_destroy(instance) class SruleViewSet(CustomModelViewSet): From 45af7513509fedf49da6473950750d0a38a2d550 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 11:32:05 +0800 Subject: [PATCH 04/29] =?UTF-8?q?feat:=20MlogSerializer=20=E5=A4=84?= =?UTF-8?q?=E7=90=86=20work=5Fstart=5Ftime=20=E7=9A=84=20bug2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 6a74d8a0..d8a45a78 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -639,6 +639,10 @@ class MlogSerializer(CustomModelSerializer): attrs['handle_date'] = mtask.end_date if attrs['handle_date'] != handle_date: raise ParseError('任务日期与生产日期不一致') + else: + attrs['handle_date'] = handle_date + else: + attrs['handle_date'] = handle_date handle_user = attrs.get('handle_user', None) if handle_user is None and hasattr(self, "request"): From 28671451b095c53ed10f6217acefc3e068b59aad Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 12:15:29 +0800 Subject: [PATCH 05/29] =?UTF-8?q?feat:=20mlogchange=E6=94=AF=E6=8C=81work?= =?UTF-8?q?=5Fstart=5Ftime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index d8a45a78..39944b65 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -639,8 +639,6 @@ class MlogSerializer(CustomModelSerializer): attrs['handle_date'] = mtask.end_date if attrs['handle_date'] != handle_date: raise ParseError('任务日期与生产日期不一致') - else: - attrs['handle_date'] = handle_date else: attrs['handle_date'] = handle_date @@ -688,8 +686,6 @@ class MlogInitSerializer(CustomModelSerializer): supplier = attrs.get('supplier', None) if not supplier: raise ParseError('外协必须选择外协单位') - if attrs.get('work_start_time', None) and 'handle_date' not in attrs: - attrs['handle_date'] = localdate(attrs['work_end_time']) # 如果已经确定产出,则自动获取qct if attrs.get("material_out", None): attrs["qct"] = Qct.get(attrs["material_out"], "process", "out") @@ -700,12 +696,14 @@ class MlogInitSerializer(CustomModelSerializer): class MlogChangeSerializer(CustomModelSerializer): class Meta: model = Mlog - fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file', 'test_user', 'test_time', 'equipment', "team"] + fields = ['id', 'work_start_time', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file', 'test_user', 'test_time', 'equipment', "team"] - # def validate(self, attrs): - # if attrs.get('work_end_time', None): - # attrs['handle_date'] = localdate(attrs['work_end_time']) - # return attrs + def update(self, instance, validated_data): + work_start_time = validated_data.get('work_start_time', None) + if work_start_time: + mgroup:Mgroup = instance.mgroup + validated_data["handle_date"], validated_data["shift"] = mgroup.get_shift(work_start_time) + return super().update(instance, validated_data) class CountJsonSerializer(serializers.Serializer): From ba0e86d834c1b85e6003d6aaf29c7f2453207ea4 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 14:30:25 +0800 Subject: [PATCH 06/29] =?UTF-8?q?fix:=20ftestwork=20submit=20=E6=A0=A1?= =?UTF-8?q?=E9=AA=8Cwm=E5=92=8Cmb=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/qm/views.py b/apps/qm/views.py index 410bfd27..ae1e2b57 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -322,7 +322,7 @@ class FtestWorkViewSet(CustomModelViewSet): ins:FtestWork = self.get_object() if ins.ticket: raise ParseError('该检验工作存在审批!') - if ins.wm is None or ins.mb is None: + if ins.wm is None and ins.mb is None: raise ParseError('该检验工作未关联库存') if ins.submit_time is None: ftestwork_submit(ins, request.user) From a6b320bad6ee7f43154f656571f5f2515c6939b2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 15:16:55 +0800 Subject: [PATCH 07/29] =?UTF-8?q?feat:=20route=20update=20=E6=97=B6from=5F?= =?UTF-8?q?route=E5=AD=98=E5=9C=A8=E5=88=99=E4=B8=8D=E5=8F=AF=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=85=B3=E9=94=AE=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mtm/views.py b/apps/mtm/views.py index 36508f4a..c0a6506c 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -378,7 +378,7 @@ class RouteViewSet(CustomModelViewSet): if routepack and routepack.state != RoutePack.RP_S_CREATE: raise ParseError('该工艺路线非创建中不可编辑') ins_n:Route = serializer.save() - if ins_n.material_in != old_m_in or ins_n.material_out != old_m_out or ins_n.process != process: + if ins.from_route and ins_n.material_in != old_m_in or ins_n.material_out != old_m_out or ins_n.process != process: raise ParseError("该工艺步骤被其他步骤引用, 无法修改关键信息") def perform_destroy(self, instance:Route): From bf3803a0e8e79406087ab8fe0238f412ec4767e3 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 15:17:59 +0800 Subject: [PATCH 08/29] =?UTF-8?q?feat:=20mlog=5Fsubmit=20=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E6=93=8D=E4=BD=9C=E6=97=B6=E9=97=B4=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 45b0808b..f7dd0c0b 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -152,6 +152,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): """ 生产日志提交后需要执行的操作 """ + if mlog.work_start_time > timezone.now(): + raise ParseError('操作开始时间不能晚于当前时间') if mlog.work_start_time and mlog.work_end_time and mlog.work_end_time < mlog.work_start_time: raise ParseError('操作结束时间不能早于操作开始时间') if mlog.count_real == 0: From 7d2f11f194939da5cd0139742b1a18e6a69dc910 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 15:22:29 +0800 Subject: [PATCH 09/29] =?UTF-8?q?feat:=20route=20update=20=E6=97=B6from=5F?= =?UTF-8?q?route=E5=AD=98=E5=9C=A8=E5=88=99=E4=B8=8D=E5=8F=AF=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=85=B3=E9=94=AE=E4=BF=A1=E6=81=AF2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mtm/views.py b/apps/mtm/views.py index c0a6506c..e773c863 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -378,7 +378,7 @@ class RouteViewSet(CustomModelViewSet): if routepack and routepack.state != RoutePack.RP_S_CREATE: raise ParseError('该工艺路线非创建中不可编辑') ins_n:Route = serializer.save() - if ins.from_route and ins_n.material_in != old_m_in or ins_n.material_out != old_m_out or ins_n.process != process: + if Route.objects.filter(from_route__id=ins.id).exists() and ins_n.material_in != old_m_in or ins_n.material_out != old_m_out or ins_n.process != process: raise ParseError("该工艺步骤被其他步骤引用, 无法修改关键信息") def perform_destroy(self, instance:Route): From 872e59ffe18569dac0c3faf7cac544ef9ad794d2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 15:53:24 +0800 Subject: [PATCH 10/29] =?UTF-8?q?feat:=20route=20update=20=E6=97=B6from=5F?= =?UTF-8?q?route=E5=AD=98=E5=9C=A8=E5=88=99=E4=B8=8D=E5=8F=AF=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E5=85=B3=E9=94=AE=E4=BF=A1=E6=81=AF3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/mtm/views.py b/apps/mtm/views.py index e773c863..d08c79a7 100644 --- a/apps/mtm/views.py +++ b/apps/mtm/views.py @@ -378,7 +378,7 @@ class RouteViewSet(CustomModelViewSet): if routepack and routepack.state != RoutePack.RP_S_CREATE: raise ParseError('该工艺路线非创建中不可编辑') ins_n:Route = serializer.save() - if Route.objects.filter(from_route__id=ins.id).exists() and ins_n.material_in != old_m_in or ins_n.material_out != old_m_out or ins_n.process != process: + if Route.objects.filter(from_route__id=ins.id).exists() and (ins_n.material_in != old_m_in or ins_n.material_out != old_m_out or ins_n.process != process): raise ParseError("该工艺步骤被其他步骤引用, 无法修改关键信息") def perform_destroy(self, instance:Route): From c4539260a80e57fb71eed3ddf8e44da7cd7acdcf Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 2 Sep 2025 16:45:40 +0800 Subject: [PATCH 11/29] =?UTF-8?q?feat:=20=E5=85=89=E8=8A=AF=E6=89=B9?= =?UTF-8?q?=E6=AC=A1=E7=BB=9F=E8=AE=A1=E5=A2=9E=E5=8A=A0=E7=8F=AD=E6=AC=A1?= =?UTF-8?q?=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/scripts/batch_gxerp.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/wpm/scripts/batch_gxerp.py b/apps/wpm/scripts/batch_gxerp.py index 11f8d633..8758d880 100644 --- a/apps/wpm/scripts/batch_gxerp.py +++ b/apps/wpm/scripts/batch_gxerp.py @@ -29,6 +29,7 @@ def main(batch: str, mgroup_obj): if mlogb1_qs.exists(): data[f"{mgroup_name}_日期"] = [] data[f"{mgroup_name}_操作人"] = [] + data[f"{mgroup_name}_班次"] = [] data[f"{mgroup_name}_count_use"] = 0 data[f"{mgroup_name}_count_real"] = 0 data[f"{mgroup_name}_count_ok"] = 0 @@ -47,6 +48,8 @@ def main(batch: str, mgroup_obj): data[f"{mgroup_name}_操作人"].append(item.mlog.handle_user) if item.mlog.handle_date: data[f"{mgroup_name}_日期"].append(item.mlog.handle_date) + if item.mlog.shift: + data[f"{mgroup_name}_班次"].append(item.mlog.shift.name) data[f"{mgroup_name}_count_real"] += item.count_real data[f"{mgroup_name}_count_ok"] += item.count_ok data[f"{mgroup_name}_count_ok_full"] += item.count_ok_full if item.count_ok_full else 0 @@ -80,6 +83,8 @@ def main(batch: str, mgroup_obj): data[f"{mgroup_name}_日期"] = ";".join([item.strftime("%Y-%m-%d") for item in data[f"{mgroup_name}_日期"]]) data[f"{mgroup_name}_操作人"] = list(set(data[f"{mgroup_name}_操作人"])) data[f"{mgroup_name}_操作人"] = ";".join([item.name for item in data[f"{mgroup_name}_操作人"]]) + data[f"{mgroup_name}_班次"] = list(set(data[f"{mgroup_name}_班次"])) + data[f"{mgroup_name}_班次"] = ";".join([item for item in data[f"{mgroup_name}_班次"]]) mlogb2_qs = Mlogb.objects.filter(mlog__submit_time__isnull=False, From f82db7bb6f446775cb7b022e8a483cab40a2740f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 3 Sep 2025 11:27:58 +0800 Subject: [PATCH 12/29] =?UTF-8?q?feat:=20=E5=AF=BC=E5=85=A5=E7=89=A9?= =?UTF-8?q?=E6=96=99=E6=98=8E=E7=BB=86=E6=97=B6=E5=8F=AF=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=89=B9=E6=AC=A1=E5=8F=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/services_daoru.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/inm/services_daoru.py b/apps/inm/services_daoru.py index f4ea563a..6178c576 100644 --- a/apps/inm/services_daoru.py +++ b/apps/inm/services_daoru.py @@ -145,6 +145,10 @@ def daoru_mioitems(path:str, mio:MIO): material = Material.objects.get(number=material_number) except Exception as e: raise ParseError(f"未找到物料:{material_number} {e}") + if not batch and material.bin_number_main: + batch = material.bin_number_main + else: + raise ParseError(f"第{ind}行批次为空") count = sheet[f"c{ind}"].value warehouse_name = sheet[f"d{ind}"].value try: From cc451637759b7a88fd9e8469d3a48d3bb5676741 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 08:53:37 +0800 Subject: [PATCH 13/29] =?UTF-8?q?feat:=20mlog=5Fsubmit=20mlogbdefect?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AD=9B=E9=80=89=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index f7dd0c0b..7dae7d1e 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -205,7 +205,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): for item in m_ins: mbd_qs = MlogbDefect.get_defect_qs_from_mlogb(item) for itemx in mbd_qs: - if itemx.defect: + if itemx.defect and itemx.count > 0: m_ins_bl_list.append((item.material_in, item.batch, itemx.count, itemx.defect, item)) else: m_ins_list = [(material_in, mlog.batch, mlog.count_use, None, mlog)] @@ -284,7 +284,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): # if item.material_out.tracking == Material.MA_TRACKING_SINGLE: # Mlogbw.cal_count_notok(item) for itemx in mbd_qs: - m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item)) + if itemx.count > 0: + m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item)) # # 获取所有主要的不合格项/先暂时保留 # bw_qs = Mlogbw.objects.filter(mlogb=item) # defectIds= Ftest.objects.filter(mlogbw_ftest__in=bw_qs).exclude(defect_main=None).values_list("defect_main__id", flat=True).distinct() @@ -437,7 +438,8 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): # if item.material_out.tracking == Material.MA_TRACKING_SINGLE: # Mlogbw.cal_count_notok(item) for itemx in mbd_qs: - m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item)) + if itemx.count > 0: + m_outs_list.append((item.material_out, item.batch, itemx.count, 0, itemx.defect, item)) # if item.material_out.tracking == Material.MA_TRACKING_SINGLE: # # 获取所有主要的不合格项 # bw_qs = Mlogbw.objects.filter(mlogb=item) @@ -532,7 +534,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): for item in m_ins: mbd_qs = MlogbDefect.get_defect_qs_from_mlogb(item) for itemx in mbd_qs: - if itemx.defect: + if itemx.defect and itemx.count > 0: m_ins_bl_list.append((item.material_in, item.batch, itemx.count, itemx.defect, item)) else: m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in, mlog)] From abd1ac9d56e1fb68e23935d3a5454da8720d772a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 08:54:21 +0800 Subject: [PATCH 14/29] =?UTF-8?q?feat:=20batch=5Fbxerp=E8=80=83=E8=99=91ml?= =?UTF-8?q?ogbw=5Ffrom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/scripts/batch_bxerp.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/wpm/scripts/batch_bxerp.py b/apps/wpm/scripts/batch_bxerp.py index 80d14191..d16dc40a 100644 --- a/apps/wpm/scripts/batch_bxerp.py +++ b/apps/wpm/scripts/batch_bxerp.py @@ -1,6 +1,6 @@ from apps.wpm.models import BatchSt import logging -from apps.wpm.models import Mlogb, MlogbDefect +from apps.wpm.models import Mlogb, Mlogbw, MlogbDefect from apps.mtm.models import Mgroup import decimal from django.db.models import Sum @@ -41,10 +41,14 @@ def main(batch: str, mgroup_obj:Mgroup=None): for item in mlogb1_qs: # 找到对应的输入 mlogb_from:Mlogb = item.mlogb_from + mlogbw_from:Mlogbw = item.mlogbw_from if mlogb_from: mlogb_q_ids.append(mlogb_from.id) data[f"{mgroup_name}_count_use"] += mlogb_from.count_use data[f"{mgroup_name}_count_pn_jgqbl"] += mlogb_from.count_pn_jgqbl + if mlogbw_from: + data[f"{mgroup_name}_count_use"] += 1 + data[f"{mgroup_name}_count_pn_jgqbl"] += 0 if item.mlog.handle_user: data[f"{mgroup_name}_操作人"].append(item.mlog.handle_user) if item.mlog.handle_date: From 6104a2e6bec6a59d7308f86353cab0a8b188ed7a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 10:08:44 +0800 Subject: [PATCH 15/29] =?UTF-8?q?feat:=20=E5=AF=BC=E5=85=A5=E7=89=A9?= =?UTF-8?q?=E6=96=99=E6=98=8E=E7=BB=86=E6=97=B6=E5=8F=AF=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=89=B9=E6=AC=A1=E5=8F=B72?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/services_daoru.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/inm/services_daoru.py b/apps/inm/services_daoru.py index 6178c576..014c0765 100644 --- a/apps/inm/services_daoru.py +++ b/apps/inm/services_daoru.py @@ -138,7 +138,7 @@ def daoru_mioitems(path:str, mio:MIO): mioitems = [] ind = 2 - while sheet[f"b{ind}"].value: + while sheet[f"a{ind}"].value: batch = sheet[f"b{ind}"].value material_number = sheet[f"a{ind}"].value try: From 3d188a72f38ece0d133153b8570bbff8594e0a66 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 10:25:42 +0800 Subject: [PATCH 16/29] =?UTF-8?q?feat:=20=E5=AF=BC=E5=85=A5=E7=89=A9?= =?UTF-8?q?=E6=96=99=E6=98=8E=E7=BB=86=E6=97=B6=E5=8F=AF=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=89=B9=E6=AC=A1=E5=8F=B73?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/services_daoru.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/inm/services_daoru.py b/apps/inm/services_daoru.py index 014c0765..a1c54819 100644 --- a/apps/inm/services_daoru.py +++ b/apps/inm/services_daoru.py @@ -145,7 +145,9 @@ def daoru_mioitems(path:str, mio:MIO): material = Material.objects.get(number=material_number) except Exception as e: raise ParseError(f"未找到物料:{material_number} {e}") - if not batch and material.bin_number_main: + if batch: + pass + elif material.bin_number_main: batch = material.bin_number_main else: raise ParseError(f"第{ind}行批次为空") From e6a1363b43a07afd9bf026e51d59a02a9d0eb3a5 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 10:40:52 +0800 Subject: [PATCH 17/29] =?UTF-8?q?feat:=20=E5=AF=BC=E5=85=A5=E7=89=A9?= =?UTF-8?q?=E6=96=99=E6=98=8E=E7=BB=86=E6=97=B6=E5=8F=AF=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=89=B9=E6=AC=A1=E5=8F=B7=E4=B8=BA=20=E6=97=A0=E6=89=B9?= =?UTF-8?q?=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/services_daoru.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/inm/services_daoru.py b/apps/inm/services_daoru.py index a1c54819..ce792c04 100644 --- a/apps/inm/services_daoru.py +++ b/apps/inm/services_daoru.py @@ -150,7 +150,7 @@ def daoru_mioitems(path:str, mio:MIO): elif material.bin_number_main: batch = material.bin_number_main else: - raise ParseError(f"第{ind}行批次为空") + batch = "无批次" count = sheet[f"c{ind}"].value warehouse_name = sheet[f"d{ind}"].value try: From 0c08543e9cec647b81bcb6d62ababa3c1463e6bb Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 10:44:32 +0800 Subject: [PATCH 18/29] =?UTF-8?q?feat:=20=E5=AF=BC=E5=85=A5=E7=89=A9?= =?UTF-8?q?=E6=96=99=E6=98=8E=E7=BB=86=E6=97=B6=E5=8F=AF=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=89=B9=E6=AC=A1=E5=8F=B7=E4=B8=BA=20=E6=97=A0=E6=89=B9?= =?UTF-8?q?=E6=AC=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/services_daoru.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/inm/services_daoru.py b/apps/inm/services_daoru.py index ce792c04..defd7ab6 100644 --- a/apps/inm/services_daoru.py +++ b/apps/inm/services_daoru.py @@ -147,8 +147,6 @@ def daoru_mioitems(path:str, mio:MIO): raise ParseError(f"未找到物料:{material_number} {e}") if batch: pass - elif material.bin_number_main: - batch = material.bin_number_main else: batch = "无批次" count = sheet[f"c{ind}"].value From 4cffb8a563b4dd53cfbecd86955ce3b1486784b8 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 10:55:56 +0800 Subject: [PATCH 19/29] =?UTF-8?q?feat:=20=E5=87=BA=E5=85=A5=E5=BA=93?= =?UTF-8?q?=E6=98=8E=E7=BB=86=E5=8F=AF=E9=BB=98=E8=AE=A4=E6=89=B9=E6=AC=A1?= =?UTF-8?q?=E4=B8=BA=E6=97=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/serializers.py | 4 +++- apps/inm/services_daoru.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/inm/serializers.py b/apps/inm/serializers.py index 3521d692..6770119c 100644 --- a/apps/inm/serializers.py +++ b/apps/inm/serializers.py @@ -153,7 +153,9 @@ class MIOItemCreateSerializer(CustomModelSerializer): validated_data["batch"] = wm.batch material: Material = validated_data['material'] - batch = validated_data['batch'] + batch = validated_data.get("batch", None) + if not batch: + batch = "无" if material.is_hidden: raise ParseError('隐式物料不可出入库') if mio.type in [MIO.MIO_TYPE_RETURN_IN, MIO.MIO_TYPE_BORROW_OUT]: diff --git a/apps/inm/services_daoru.py b/apps/inm/services_daoru.py index defd7ab6..be19207e 100644 --- a/apps/inm/services_daoru.py +++ b/apps/inm/services_daoru.py @@ -148,7 +148,7 @@ def daoru_mioitems(path:str, mio:MIO): if batch: pass else: - batch = "无批次" + batch = "无" count = sheet[f"c{ind}"].value warehouse_name = sheet[f"d{ind}"].value try: From 01b30e21d32c0d82a7ce5962c88fc0f482963939 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 14:42:14 +0800 Subject: [PATCH 20/29] =?UTF-8?q?feat:=20=E5=87=BA=E5=85=A5=E5=BA=93?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E6=B7=BB=E5=8A=A0=E4=B9=90=E8=A7=82=E9=94=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/views.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/inm/views.py b/apps/inm/views.py index 0239e605..3b094a3f 100644 --- a/apps/inm/views.py +++ b/apps/inm/views.py @@ -206,12 +206,13 @@ class MIOViewSet(CustomModelViewSet): if ins.state != MIO.MIO_CREATE: raise ParseError('记录状态异常') with transaction.atomic(): - ins.submit_time = timezone.now() - ins.state = MIO.MIO_SUBMITED - ins.submit_user = request.user - ins.update_by = request.user - ins.save() - InmService.update_inm(ins) + now = timezone.now() + updated_count = MIO.objects.filter(id=ins.id, submit_time__isnull=True).update( + submit_time=now, update_time=now, state=MIO.MIO_SUBMITED, submit_user=request.user, update_by=request.user) + if updated_count == 1: + InmService.update_inm(ins) + else: + raise ParseError('记录正在处理中,请稍后再试') InmService.update_material_count(ins) return Response(MIOListSerializer(instance=ins).data) @@ -228,11 +229,12 @@ class MIOViewSet(CustomModelViewSet): if ins.submit_user != user: raise ParseError('非提交人不可撤回') with transaction.atomic(): - ins.submit_time = None - ins.state = MIO.MIO_CREATE - ins.update_by = user - ins.save() - InmService.update_inm(ins, is_reverse=True) + updated_count = MIO.objects.filter(id=ins.id, submit_time__isnull=False).update( + submit_time=None, update_time=timezone.now(), state=MIO.MIO_CREATE, submit_user=None, update_by=request.user) + if updated_count == 1: + InmService.update_inm(ins, is_reverse=True) + else: + raise ParseError('记录正在处理中,请稍后再试') InmService.update_material_count(ins) return Response() From 2524feca72ac8cdc2adc0b83d9360c8a7df427df Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 15:07:07 +0800 Subject: [PATCH 21/29] =?UTF-8?q?feat:=20=E5=8F=96=E6=B6=88=E6=9C=80?= =?UTF-8?q?=E5=90=8E=E4=B8=80=E6=AD=A5=E4=BA=A7=E5=87=BA=E4=B8=8E=E5=B7=A5?= =?UTF-8?q?=E8=89=BA=E5=8C=85=E4=B8=8D=E4=B8=80=E8=87=B4=20=E7=9A=84?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/services.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/mtm/services.py b/apps/mtm/services.py index 8f4155f1..626b95b4 100644 --- a/apps/mtm/services.py +++ b/apps/mtm/services.py @@ -155,12 +155,12 @@ def bind_routepack(ticket: Ticket, transition, new_ticket_data: dict): raise ParseError('缺少步骤') r_qs = Route.objects.filter(routepack=routepack).order_by('sort', 'process__sort', 'create_time') first_route = r_qs.first() - last_route = r_qs.last() if first_route.batch_bind: first_route.batch_bind = False first_route.save(update_fields=['batch_bind']) - if last_route.material_out != routepack.material: - raise ParseError('最后一步产出与工艺包不一致') + # last_route = r_qs.last() + # if last_route.material_out != routepack.material: + # raise ParseError('最后一步产出与工艺包不一致') ticket_data = ticket.ticket_data ticket_data.update({ 't_model': 'routepack', From 65726e967f3454a8d5b797ab23c7cd18d4c51aa1 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 16:48:10 +0800 Subject: [PATCH 22/29] =?UTF-8?q?feat:=20update=5Fmb=5Fitem=20defect?= =?UTF-8?q?=E5=A4=84=E7=90=86=E6=9B=B4=E4=B8=A5=E8=B0=A8?= 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 145f9568..67d47bc4 100644 --- a/apps/inm/services.py +++ b/apps/inm/services.py @@ -398,7 +398,7 @@ class InmService: if change_count < 0: raise ParseError("存在负数!") state = WMaterial.WM_OK - if defect: + if defect and defect.okcate in [Defect.DEFECT_NOTOK]: state = WMaterial.WM_NOTOK mb, _ = MaterialBatch.objects.get_or_create( material=material, From 65d47008a4ac75ed5a9286ff90c6939ad8ff1097 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 16:48:41 +0800 Subject: [PATCH 23/29] =?UTF-8?q?feat:=20mlogbdefect=E6=B7=BB=E5=8A=A0coun?= =?UTF-8?q?t=5Fhas=20=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0123_mlogbdefect_count_has.py | 18 +++++++++++++++++ apps/wpm/models.py | 20 +++++++++++++++---- 2 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 apps/wpm/migrations/0123_mlogbdefect_count_has.py diff --git a/apps/wpm/migrations/0123_mlogbdefect_count_has.py b/apps/wpm/migrations/0123_mlogbdefect_count_has.py new file mode 100644 index 00000000..4ef30708 --- /dev/null +++ b/apps/wpm/migrations/0123_mlogbdefect_count_has.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2025-09-04 08:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0122_auto_20250827_1522'), + ] + + operations = [ + migrations.AddField( + model_name='mlogbdefect', + name='count_has', + field=models.DecimalField(decimal_places=1, default=0, max_digits=11, verbose_name='含有该缺陷的数量'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index a1766aec..7baf2930 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -477,6 +477,7 @@ class MlogbDefect(BaseModel): mlogb = models.ForeignKey(Mlogb, verbose_name='生产记录', on_delete=models.CASCADE) defect = models.ForeignKey("qm.Defect", verbose_name='缺陷', on_delete=models.CASCADE, null=True, blank=True) count = models.DecimalField('数量', default=0, max_digits=11, decimal_places=1) + count_has = models.DecimalField('含有该缺陷的数量', default=0, max_digits=11, decimal_places=1) @classmethod def get_defect_qs(cls, ftype="all"): @@ -512,7 +513,7 @@ class Mlogbw(BaseModel): @classmethod def cal_count_notok(cls, mlogb: Mlogb): - from apps.qm.models import Defect + from apps.qm.models import Defect, FtestDefect # 锁定mlogb以防止并发修改 # mlogb:Mlogb = Mlogb.objects.select_for_update().get(pk=mlogb.pk) count = Mlogbw.objects.filter(mlogb=mlogb).count() @@ -523,9 +524,13 @@ class Mlogbw(BaseModel): mlogb.count_real = count count_notok = 0 count_notok_full = 0 - tqs = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False) - tqs_a = Mlogbw.objects.filter(mlogb=mlogb, ftest__is_ok=False).values("ftest__defect_main").annotate(xcount=Count('id')) - defects = {defect.id: defect for defect in Defect.objects.filter(id__in=tqs.values_list("ftest__defect_main", flat=True))} + # 个追踪的合格b类不分批 + tqs = Mlogbw.objects.filter(mlogb=mlogb, ftest__defect_main__isnull=False) + tqs_a = Mlogbw.objects.filter(mlogb=mlogb, ftest__defect_main__isnull=False).values("ftest__defect_main").annotate(xcount=Count('id')) + defect_ids = tqs.values_list("ftest__defect_main", flat=True) + tqs_has_a = FtestDefect.objects.filter(ftest__mlogbw_ftest__mlogb=mlogb, has=True).values("defect").annotate(xcount=Count('id')) + defect_ids = defect_ids.union(tqs_has_a.values_list("defect", flat=True)) + defects = {defect.id: defect for defect in Defect.objects.filter(id__in=defect_ids)} md_ids = [] for t in tqs_a: md, _ = MlogbDefect.objects.get_or_create(mlogb=mlogb, defect=defects[t["ftest__defect_main"]]) @@ -535,6 +540,13 @@ class Mlogbw(BaseModel): count_notok += t["xcount"] if defects[t["ftest__defect_main"]].okcate != 10: count_notok_full += t["xcount"] + + for t2 in tqs_has_a: + md, _ = MlogbDefect.objects.get_or_create(mlogb=mlogb, defect=defects[t2["defect"]], defaults={"count": 0}) + md.count_has = t2["xcount"] + md.save() + md_ids.append(md.id) + MlogbDefect.objects.filter(mlogb=mlogb).exclude(id__in=md_ids).delete() mlogb.count_notok = count_notok mlogb.count_ok = count - mlogb.count_notok From a7fd4b944885a829288a499b893025a7b0e9380c Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 16:59:20 +0800 Subject: [PATCH 24/29] =?UTF-8?q?feat:=20MlogbDefect=20=E6=B7=BB=E5=8A=A0c?= =?UTF-8?q?ount=5Fhas=20=E7=9A=84=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 39944b65..842a3d8e 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -216,12 +216,17 @@ class MlogbDefectSerializer(CustomModelSerializer): defect_okcate = serializers.CharField(source="defect.okcate", read_only=True) class Meta: model = MlogbDefect - fields = ["id", "defect_name", "count", "mlogb", "defect", "defect_okcate"] + fields = ["id", "defect_name", "count", "mlogb", "defect", "defect_okcate", "count_has"] read_only_fields = EXCLUDE_FIELDS_BASE + ["mlogb"] + extra_kwargs = { + 'count_has': {'required': False}, + } def validate(self, attrs): if attrs["count"] < 0: raise serializers.ValidationError("存在负数!") + if "count_has" not in attrs or attrs["count_has"] < attrs["count"]: + attrs["count_has"] = attrs["count"] return attrs class MlogbSerializer(CustomModelSerializer): From f1aa9229466f48f42dfde51d335e2598735d6801 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 17:08:19 +0800 Subject: [PATCH 25/29] fix: mlogbwstarttest bug --- apps/wpm/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 842a3d8e..ddfefe74 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -956,7 +956,7 @@ class MlogbwStartTestSerializer(serializers.Serializer): if mlogbw.ftest: existing_ftests[mlogbw.ftest_id] = mlogbw.ftest else: - ftest = Ftest(mlogbw=mlogbw, test_date=test_date, qct=qct) + ftest = Ftest(test_date=test_date, qct=qct, test_user=test_user, type="process") new_ftests.append(ftest) mlogbws_to_update.append(mlogbw) From 026ebccef52c421444fd17f723c7a60dab6f31e6 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 17:18:38 +0800 Subject: [PATCH 26/29] fix: mlogbwstarttest bug2 --- apps/wpm/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index ddfefe74..28ae5893 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -956,7 +956,7 @@ class MlogbwStartTestSerializer(serializers.Serializer): if mlogbw.ftest: existing_ftests[mlogbw.ftest_id] = mlogbw.ftest else: - ftest = Ftest(test_date=test_date, qct=qct, test_user=test_user, type="process") + ftest = Ftest(test_date=test_date, qct=qct, test_user=test_user, type="process", id=idWorker.get_id()) new_ftests.append(ftest) mlogbws_to_update.append(mlogbw) From a6fcdab836bb8e96cc7738108ced12d800a6634f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 17:20:31 +0800 Subject: [PATCH 27/29] fix: mlogbwstarttest bug3 --- apps/wpm/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 28ae5893..32cf7f6e 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -916,7 +916,7 @@ class MlogbwCreateUpdateSerializer(CustomModelSerializer): class MlogbwStartTestSerializer(serializers.Serializer): mlogbw_ids = serializers.ListField(child=serializers.CharField(), label="mlogbwId列表") - test_equip = serializers.CharField(label="测试设备", allow_null=True, required=False) + test_equip = serializers.CharField(label="测试设备", allow_null=True, required=False, allow_blank=True) test_user = serializers.CharField(label="测试人员") defects = serializers.ListField(child=serializers.CharField(), required=False, allow_null=True, label="缺陷项列表") testitems = serializers.ListField(child=serializers.CharField(), required=False, allow_null=True, label="测试项列表") From c20580e263595c8978fb16678e755c14e7361079 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 4 Sep 2025 17:23:00 +0800 Subject: [PATCH 28/29] fix: mlogbwstarttest bug4 --- apps/wpm/serializers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 32cf7f6e..a8ec4c6f 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -994,7 +994,7 @@ class MlogbwStartTestSerializer(serializers.Serializer): else: # 新记录,需要创建 defects_to_create.append( - FtestDefect(ftest=ftest, defect=defect, test_user=test_user) + FtestDefect(ftest=ftest, defect=defect, test_user=test_user, id=idWorker.get_id()) ) # 批量创建新记录 @@ -1033,7 +1033,8 @@ class MlogbwStartTestSerializer(serializers.Serializer): ftest=ftest, testitem=testitem, test_user=test_user, - test_equip=test_equip + test_equip=test_equip, + id=idWorker.get_id() ) ) From 41c1653d132b0133a75caa74d4082fb07c99e782 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 5 Sep 2025 09:47:20 +0800 Subject: [PATCH 29/29] =?UTF-8?q?feat:=20ftest=E9=BB=98=E8=AE=A4=E4=B8=BA?= =?UTF-8?q?=E5=90=88=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/migrations/0053_alter_ftest_is_ok.py | 18 ++++++++++++++++++ apps/qm/models.py | 2 +- apps/wpm/serializers.py | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 apps/qm/migrations/0053_alter_ftest_is_ok.py diff --git a/apps/qm/migrations/0053_alter_ftest_is_ok.py b/apps/qm/migrations/0053_alter_ftest_is_ok.py new file mode 100644 index 00000000..92b5f83c --- /dev/null +++ b/apps/qm/migrations/0053_alter_ftest_is_ok.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2025-09-05 01:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0052_auto_20250718_1558'), + ] + + operations = [ + migrations.AlterField( + model_name='ftest', + name='is_ok', + field=models.BooleanField(default=True, verbose_name='是否合格'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index 5ec00882..b724a228 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -337,7 +337,7 @@ class Ftest(CommonBDModel): User, verbose_name='操作人', on_delete=models.CASCADE, related_name='ftest_test_user') check_user = models.ForeignKey( User, verbose_name='专检人', on_delete=models.CASCADE, related_name='ftest_check_user', null=True, blank=True) - is_ok = models.BooleanField('是否合格', default=False) + is_ok = models.BooleanField('是否合格', default=True) note = models.TextField('备注', default='', blank=True) ftest_work = models.ForeignKey( FtestWork, verbose_name='关联检验工作', on_delete=models.CASCADE, null=True, blank=True) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index a8ec4c6f..f1c2f477 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -956,7 +956,7 @@ class MlogbwStartTestSerializer(serializers.Serializer): if mlogbw.ftest: existing_ftests[mlogbw.ftest_id] = mlogbw.ftest else: - ftest = Ftest(test_date=test_date, qct=qct, test_user=test_user, type="process", id=idWorker.get_id()) + ftest = Ftest(test_date=test_date, qct=qct, test_user=test_user, type="process", id=idWorker.get_id(), is_ok=True) new_ftests.append(ftest) mlogbws_to_update.append(mlogbw)