From 730aa689667b68423aea90d0fcbc8095ca01d1cc Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 28 Aug 2024 16:12:31 +0800 Subject: [PATCH 001/106] =?UTF-8?q?feat:=20tag=5Fupdate=20=E5=85=88?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6=E6=9C=AC=E5=9C=B0=E6=97=B6?= =?UTF-8?q?=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/enm/services.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/apps/enm/services.py b/apps/enm/services.py index 1fddba09..bf74f777 100644 --- a/apps/enm/services.py +++ b/apps/enm/services.py @@ -21,12 +21,9 @@ myLogger = logging.getLogger("log") def db_insert_mplogx_batch(rows): for row in rows: _, tag_val, tag_code, tag_update = row - # if '散装' in tag_code or '袋装' in tag_code: - # myLogger.info(f"db_ins_mplogx tag_val: {tag_val} tag_code: {tag_code}-------{str(type(tag_val))}") - # mpoint = Mpoint.objects.get(code=tag_code) - # tag_val = float(tag_val) - # myLogger.info(f"db_ins_mpoint_id: {mpoint.id}-------db_ins_float_val: {tag_val}") - insert_mplogx_item(tag_code, tag_val, timezone.make_aware(tag_update), {}) + if isinstance(tag_update, datetime): + tag_update = timezone.make_aware(tag_update) + insert_mplogx_item(tag_code, tag_val, tag_update, {}) def translate_eval_formula(exp_str: str, year: int, month: int, day: int, hour: int): """ From 43d0d90e4189cfeeb30a5ab4de9fe9faeeae0325 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 28 Aug 2024 16:17:14 +0800 Subject: [PATCH 002/106] =?UTF-8?q?fix:=20tag=5Fupdate=20=E5=85=88?= =?UTF-8?q?=E5=88=A4=E6=96=AD=E6=98=AF=E5=90=A6=E6=9C=AC=E5=9C=B0=E6=97=B6?= =?UTF-8?q?=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/enm/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/enm/services.py b/apps/enm/services.py index bf74f777..86fdff79 100644 --- a/apps/enm/services.py +++ b/apps/enm/services.py @@ -21,7 +21,7 @@ myLogger = logging.getLogger("log") def db_insert_mplogx_batch(rows): for row in rows: _, tag_val, tag_code, tag_update = row - if isinstance(tag_update, datetime): + if tag_update.tzinfo is None: tag_update = timezone.make_aware(tag_update) insert_mplogx_item(tag_code, tag_val, tag_update, {}) From 4ac5d1f1f7b8ff5ef9c2d779b910cb03bfa8e96c Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 28 Aug 2024 16:27:35 +0800 Subject: [PATCH 003/106] =?UTF-8?q?feat:=20xscript=E6=B7=BB=E5=8A=A0logger?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/enm/xscript.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/enm/xscript.py b/apps/enm/xscript.py index 613fbf9c..c78bd851 100644 --- a/apps/enm/xscript.py +++ b/apps/enm/xscript.py @@ -3,6 +3,8 @@ from apps.utils.sql import DbConnection from datetime import datetime, timedelta from apps.enm.services import db_insert_mplogx_batch import requests +import logging +myLogger = logging.getLogger("log") def main(xscript, mcodes_list): exec(xscript.code) From da3b0f62e5ec84926bc0e3c9867d2275fa6830d9 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 28 Aug 2024 17:09:24 +0800 Subject: [PATCH 004/106] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0change=5Fdata?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../enm/migrations/0044_xscript_change_data.py | 18 ++++++++++++++++++ apps/enm/models.py | 1 + apps/enm/serializers.py | 2 +- apps/enm/views.py | 10 ++++++++++ 4 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 apps/enm/migrations/0044_xscript_change_data.py diff --git a/apps/enm/migrations/0044_xscript_change_data.py b/apps/enm/migrations/0044_xscript_change_data.py new file mode 100644 index 00000000..0760d372 --- /dev/null +++ b/apps/enm/migrations/0044_xscript_change_data.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2024-08-28 08:51 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('enm', '0043_xscript'), + ] + + operations = [ + migrations.AddField( + model_name='xscript', + name='change_data', + field=models.JSONField(blank=True, default=dict, null=True, verbose_name='变更数据'), + ), + ] diff --git a/apps/enm/models.py b/apps/enm/models.py index d778cb2f..cce4e43e 100644 --- a/apps/enm/models.py +++ b/apps/enm/models.py @@ -8,6 +8,7 @@ class Xscript(BaseModel): name = models.CharField("脚本名称", max_length=50) code = models.TextField("脚本内容", null=True, blank=True) base_data = models.JSONField("基础数据", default=dict, null=True, blank=True) + change_data = models.JSONField("变更数据", default=dict, null=True, blank=True) myschedule = models.ForeignKey('system.myschedule', verbose_name='周期', on_delete=models.SET_NULL, null=True, blank=True) periodictask = models.ForeignKey(PeriodicTask, verbose_name='关联定时任务', on_delete=models.CASCADE, related_name='xscript_periodictask', null=True, blank=True) diff --git a/apps/enm/serializers.py b/apps/enm/serializers.py index c7fd3331..7593c0d5 100644 --- a/apps/enm/serializers.py +++ b/apps/enm/serializers.py @@ -201,7 +201,7 @@ class XscriptSerializer(CustomModelSerializer): class Meta: model = Xscript fields = "__all__" - read_only_fields = EXCLUDE_FIELDS_BASE + ['periodictask'] + read_only_fields = EXCLUDE_FIELDS_BASE + ['periodictask', 'change_data'] def validate(self, attrs): code = attrs['code'] diff --git a/apps/enm/views.py b/apps/enm/views.py index 6552d645..17babbaa 100644 --- a/apps/enm/views.py +++ b/apps/enm/views.py @@ -92,6 +92,16 @@ class XscriptViewSet(CustomModelViewSet): periodictask.save() return Response() + @action(methods=['put'], detail=True, perms_map={'put': 'xscript.update'}) + def change_data(self, request, pk=None): + """修改变动数据 + + 修改变动数据 + """ + obj: Xscript = self.get_object() + obj.change_data = request.data.get('change_data', {}) + return Response() + @transaction.atomic def perform_destroy(self, instance): periodictask = instance.periodictask From cf10f028290ff850ba0462d2c7f9fdce495aed8b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 28 Aug 2024 17:14:49 +0800 Subject: [PATCH 005/106] =?UTF-8?q?fix:=20xscript=20change=5Fdata=20?= =?UTF-8?q?=E5=8F=98=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/enm/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/enm/views.py b/apps/enm/views.py index 17babbaa..9b8a8de5 100644 --- a/apps/enm/views.py +++ b/apps/enm/views.py @@ -100,6 +100,7 @@ class XscriptViewSet(CustomModelViewSet): """ obj: Xscript = self.get_object() obj.change_data = request.data.get('change_data', {}) + obj.save(update_fields=['change_data']) return Response() @transaction.atomic From e94996471f7126c9e49efcf870174540dbbbe1c8 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 29 Aug 2024 09:28:39 +0800 Subject: [PATCH 006/106] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96enstat2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/enm/tasks.py | 35 ++++++++++++++++++++++------------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/apps/enm/tasks.py b/apps/enm/tasks.py index f6ea1f5d..22ce1fef 100644 --- a/apps/enm/tasks.py +++ b/apps/enm/tasks.py @@ -27,6 +27,7 @@ from apps.wpm.tasks import get_total_sec_now, cal_exp_duration_sec from apps.utils.sql import DbConnection from apps.enm.services import db_insert_mplogx_batch from apps.enm.xscript import main +from django.core.exceptions import ObjectDoesNotExist myLogger = logging.getLogger("log") @@ -685,34 +686,42 @@ def cal_enstat2(type: str, year_s: int, month_s: int, day_s: int, cascade=True): elif type == "day_s": enstat2, _ = EnStat2.objects.get_or_create(type="day_s", year_s=year_s, month_s=month_s, day_s=day_s, defaults={"year_s": year_s, "month_s": month_s, "day_s": day_s, "type": "day_s"}) # enstat2 = EnStat2.objects.select_for_update().get(id=enstat2.id) # 加锁 - material_bulk_clinker = Material.objects.get(code="bulk_clinker") # 散装熟料 - material_bulk_cement = Material.objects.get(code="bulk_cement") # 散装水泥 - material_bag_cement = Material.objects.get(code="bag_cement") # 袋装水泥 + try: + material_bulk_clinker = Material.objects.get(code="bulk_clinker") # 散装熟料 + enstat2.bulk_clinker_price = get_price_unit(material_bulk_clinker, year_s, month_s) + except ObjectDoesNotExist: + enstat2.bulk_clinker_price = 0 + try: + material_bulk_cement = Material.objects.get(code="bulk_cement") # 散装水泥 + enstat2.bulk_cement_price = get_price_unit(material_bulk_cement, year_s, month_s) + except ObjectDoesNotExist: + enstat2.bulk_cement_price = 0 + try: + material_bag_cement = Material.objects.get(code="bag_cement") # 袋装水泥 + enstat2.bag_cement_price = get_price_unit(material_bag_cement, year_s, month_s) + except ObjectDoesNotExist: + enstat2.bag_cement_price = 0 - enstat2.bulk_cement_price = get_price_unit(material_bulk_cement, year_s, month_s) - enstat2.bulk_clinker_price = get_price_unit(material_bulk_clinker, year_s, month_s) - enstat2.bag_cement_price = get_price_unit(material_bag_cement, year_s, month_s) - if type == "month_s": - enstat2.bulk_cement_val = MpointStat.objects.filter(type="month_s", mpoint__material=material_bulk_cement, year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"] + enstat2.bulk_cement_val = MpointStat.objects.filter(type="month_s", mpoint__material__code="bulk_cement", year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"] elif type == "day_s": - enstat2.bulk_cement_val = MpointStat.objects.filter(type="day_s", mpoint__material=material_bulk_cement, year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"] + enstat2.bulk_cement_val = MpointStat.objects.filter(type="day_s", mpoint__material__code="bulk_cement", year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"] if enstat2.bulk_cement_val is None: enstat2.bulk_cement_val = 0 if type == "month_s": - enstat2.bag_cement_val = MpointStat.objects.filter(type="month_s", mpoint__material=material_bag_cement, year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"] + enstat2.bag_cement_val = MpointStat.objects.filter(type="month_s", mpoint__material__code='bag_cement', year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"] elif type == "day_s": - enstat2.bag_cement_val = MpointStat.objects.filter(type="day_s", mpoint__material=material_bag_cement, year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"] + enstat2.bag_cement_val = MpointStat.objects.filter(type="day_s", mpoint__material__code='bag_cement', year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"] if enstat2.bag_cement_val is None: enstat2.bag_cement_val = 0 if type == "month_s": - enstat2.bulk_clinker_val = MpointStat.objects.filter(type="month_s", mpoint__material=material_bulk_clinker, year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"] + enstat2.bulk_clinker_val = MpointStat.objects.filter(type="month_s", mpoint__material__code='bulk_clinker', year_s=year_s, month_s=month_s).aggregate(sum=Sum("val"))["sum"] elif type == "day_s": - enstat2.bulk_clinker_val = MpointStat.objects.filter(type="day_s", mpoint__material=material_bulk_clinker, year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"] + enstat2.bulk_clinker_val = MpointStat.objects.filter(type="day_s", mpoint__material__code='bulk_clinker', year_s=year_s, month_s=month_s, day_s=day_s).aggregate(sum=Sum("val"))["sum"] if enstat2.bulk_clinker_val is None: enstat2.bulk_clinker_val = 0 From 0f0bc9bd3770813565101cc1a1e680f3d0c251fa Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 29 Aug 2024 10:28:59 +0800 Subject: [PATCH 007/106] =?UTF-8?q?feat:=20=E8=AE=A1=E7=AE=97=E6=B5=8B?= =?UTF-8?q?=E7=82=B9=E5=8F=AF=E4=B8=8D=E6=8C=87=E5=AE=9A=E7=89=A9=E6=96=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/enm/tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/enm/tasks.py b/apps/enm/tasks.py index 22ce1fef..3468470c 100644 --- a/apps/enm/tasks.py +++ b/apps/enm/tasks.py @@ -132,7 +132,7 @@ def cal_mpointstat_hour(mpointId: str, year: int, month: int, day: int, hour: in dt_hour_p= dt - datetime.timedelta(hours=1) # 上个整点 dt_hour_n= dt + datetime.timedelta(hours=1) # 下个整点 - if mpoint.material and mpoint.val_type in ['float', 'int']: # 如果计量的是物料 # 累计量 有的会清零,需要额外处理(还未做) + if (mpoint.material or mpoint.type == Mpoint.MT_COMPUTE) and mpoint.val_type in ['float', 'int']: # 如果计量的是物料 # 累计量 有的会清零,需要额外处理(还未做) params = {"mpoint": mpoint, "type": "hour"} params["year"], params["month"], params["day"], params["hour"] = year, month, day, hour val = 0 From 1855e3ae679029a510c70a50d0e38e2687c5a6ce Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 29 Aug 2024 10:51:44 +0800 Subject: [PATCH 008/106] =?UTF-8?q?feat:=20bind=5Froutepack=20=E6=97=B6?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E4=BA=A7=E5=87=BA=E6=98=AF=E5=90=A6=E4=B8=80?= =?UTF-8?q?=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/services.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/mtm/services.py b/apps/mtm/services.py index b8d483a6..fd28993d 100644 --- a/apps/mtm/services.py +++ b/apps/mtm/services.py @@ -151,10 +151,14 @@ def bind_routepack(ticket: Ticket, transition, new_ticket_data: dict): raise ParseError('重复创建工单') if not Route.objects.filter(routepack=routepack).exists(): raise ParseError('缺少步骤') - first_route = Route.objects.filter(routepack=routepack).order_by('sort', 'process__sort', 'create_time').first() + 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('最后一步产出与工艺包不一致') ticket_data = ticket.ticket_data ticket_data.update({ 't_model': 'routepack', From 81a90f31cd5d84ff45dba528c8b962e4a8d11f51 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 29 Aug 2024 13:47:16 +0800 Subject: [PATCH 009/106] =?UTF-8?q?feat:=20=E8=AE=A1=E7=AE=97=E6=B5=8B?= =?UTF-8?q?=E7=82=B9=E5=8F=AF=E4=B8=8D=E6=8C=87=E5=AE=9A=E7=89=A9=E6=96=99?= =?UTF-8?q?2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/enm/tasks.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/enm/tasks.py b/apps/enm/tasks.py index 3468470c..1dbe4b9e 100644 --- a/apps/enm/tasks.py +++ b/apps/enm/tasks.py @@ -131,7 +131,6 @@ def cal_mpointstat_hour(mpointId: str, year: int, month: int, day: int, hour: in dt = datetime.datetime(year=year, month=month, day=day, hour=hour, minute=0, second=0, tzinfo=mytz) # 整点时间 dt_hour_p= dt - datetime.timedelta(hours=1) # 上个整点 dt_hour_n= dt + datetime.timedelta(hours=1) # 下个整点 - if (mpoint.material or mpoint.type == Mpoint.MT_COMPUTE) and mpoint.val_type in ['float', 'int']: # 如果计量的是物料 # 累计量 有的会清零,需要额外处理(还未做) params = {"mpoint": mpoint, "type": "hour"} params["year"], params["month"], params["day"], params["hour"] = year, month, day, hour @@ -142,7 +141,6 @@ def cal_mpointstat_hour(mpointId: str, year: int, month: int, day: int, hour: in val = MpLogx.objects.filter(mpoint=mpoint, timex__gte=dt, timex__lt=dt_hour_n).aggregate(sum=Sum(f'val_{mpoint.val_type}'))["sum"] if val is None: val = 0 - myLogger.info(str(val), "-------val") else: mrs0 = MpLogx.objects.filter(mpoint=mpoint, timex__gte=dt_hour_p, timex__lte=dt).order_by("timex") mrs = MpLogx.objects.filter(mpoint=mpoint, timex__gte=dt, timex__lte=dt_hour_n).order_by("timex") @@ -282,7 +280,7 @@ def cal_mpointstats(is_now=1, year=None, month=None, day=None, hour=None, m_code cal_mpointstat_hour(item.id, year, month, day, hour) # 再统计计算测点 - mpoints_compute = Mpoint.objects.filter(type=Mpoint.MT_COMPUTE, enabled=True, material__isnull=False).exclude(formula="").order_by('report_sortstr', 'create_time') + mpoints_compute = Mpoint.objects.filter(type=Mpoint.MT_COMPUTE, enabled=True).exclude(formula="").order_by('report_sortstr', 'create_time') # mpoints_other_group = [] for item in mpoints_compute: # mpoints_other_group.append(cal_mpointstat_hour.s(item.id, year, month, day, hour)) From 54c7c65fe0695b3c51a5fe8dc0ee66a5c52e4081 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 29 Aug 2024 14:52:30 +0800 Subject: [PATCH 010/106] =?UTF-8?q?feat:=20=E4=BA=A7=E5=87=BA=E7=89=A9?= =?UTF-8?q?=E4=B8=BA0=E6=97=B6=E8=B7=B3=E8=BF=87revert?= 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 4840a932..f12122b7 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -339,6 +339,8 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): for mo in m_outs_list: mo_ma, mo_batch, mo_count, _, notok_sign = mo + if mo_count == 0: + continue wm_state = WMaterial.WM_OK if notok_sign is None else WMaterial.WM_NOTOK lookup = {'batch': mo_batch, 'material': mo_ma, 'mgroup': None, 'notok_sign': notok_sign, 'state': wm_state} if stored_mgroup: From ab759a76c999dab1c2289779696ae43f223f3472 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 29 Aug 2024 15:05:53 +0800 Subject: [PATCH 011/106] =?UTF-8?q?feat:=20mog=20submit=E6=97=B6=E4=BA=A7?= =?UTF-8?q?=E5=87=BA=E4=B8=BA0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index f3827da4..99bd2794 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -213,6 +213,8 @@ class MlogViewSet(CustomModelViewSet): raise ParseError('该日志未指定产出!') if not Mlogb.objects.filter(material_in__isnull=False).exists(): raise ParseError('该日志未指定消耗!') + if Mlogb.objects.filter(material_out__isnull=False, count_real=0).exists(): + raise ParseError('产出数量不能为0!') with transaction.atomic(): mlog_submit(ins, self.request.user, now) vdata_new = MlogSerializer(ins).data From 301535813b3c5efca5ea20e895f7d9b46e2bbd30 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 29 Aug 2024 15:13:08 +0800 Subject: [PATCH 012/106] =?UTF-8?q?feat:=20mlogbout=20=E6=A0=A1=E9=AA=8C?= =?UTF-8?q?=E4=B8=8D=E5=90=88=E6=A0=BC=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 064b610e..06f0bfc7 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -428,6 +428,8 @@ class MlogbOutUpdateSerializer(CustomModelSerializer): count_notok = 0 for i in attrs: if 'count_n_' in i: + if not hasattr(Mlogb, i): + raise ValidationError(f'{i}不存在') count_notok = count_notok + attrs[i] attrs['count_notok'] = count_notok if attrs['count_real'] >= attrs['count_ok'] + attrs['count_notok']: From b8994b94c1811be0a2e2b4efb867ac04cb4d881c Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 29 Aug 2024 15:43:12 +0800 Subject: [PATCH 013/106] =?UTF-8?q?feat:=20ftestwork=E5=A2=9E=E5=8A=A0filt?= =?UTF-8?q?er?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/filters.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/qm/filters.py b/apps/qm/filters.py index 018cf323..e2c1d069 100644 --- a/apps/qm/filters.py +++ b/apps/qm/filters.py @@ -30,6 +30,8 @@ class FtestWorkFilter(filters.FilterSet): fields = { "material__process__name": ["exact", "contains"], "material": ["exact"], + "wm": ["exact"], + "mb": ["exact"], "batch": ["exact"], "type": ["exact"], "type2": ["exact"], From 5289e712805d6e6889b3e79620ddb4a84b6be3ef Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 30 Aug 2024 09:21:29 +0800 Subject: [PATCH 014/106] =?UTF-8?q?feat:=20wmaterial=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=A4=96=E5=8D=8F=E5=AD=97=E6=AE=B5=E5=8F=8A=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/filters.py | 3 ++- .../wpm/migrations/0063_wmaterial_supplier.py | 20 +++++++++++++++++++ apps/wpm/models.py | 1 + apps/wpm/serializers.py | 1 + apps/wpm/services.py | 3 +++ apps/wpm/views.py | 2 +- 6 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 apps/wpm/migrations/0063_wmaterial_supplier.py diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index 06f4217d..5499c14b 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -50,7 +50,8 @@ class WMaterialFilter(filters.FilterSet): "mgroup__name": ["exact", "in"], "count": ["gte", "lte", "exact"], "notok_sign": ["exact", "in", "isnull"], - "count_xtest": ["gte", "isnull"] + "count_xtest": ["gte", "isnull"], + "supplier": ["exact"], } class MlogFilter(filters.FilterSet): diff --git a/apps/wpm/migrations/0063_wmaterial_supplier.py b/apps/wpm/migrations/0063_wmaterial_supplier.py new file mode 100644 index 00000000..7948d9dc --- /dev/null +++ b/apps/wpm/migrations/0063_wmaterial_supplier.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.12 on 2024-08-30 01:17 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pum', '0008_auto_20240731_1829'), + ('wpm', '0062_auto_20240828_1052'), + ] + + operations = [ + migrations.AddField( + model_name='wmaterial', + name='supplier', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='pum.supplier', verbose_name='外协供应商'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 41237f6f..4d2f3026 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -97,6 +97,7 @@ class WMaterial(CommonBDModel): state = models.PositiveSmallIntegerField('状态', default=10, choices=((10, '合格'), (20, '不合格'), (30, '返修'), (40, '检验'), (50, '报废'))) material = models.ForeignKey( Material, verbose_name='物料', on_delete=models.CASCADE, related_name='wm_m') + supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True) mgroup = models.ForeignKey(Mgroup, verbose_name='所在工段', on_delete=models.CASCADE, null=True, blank=True) batch = models.CharField('批次号', max_length=50) count = models.PositiveIntegerField('当前数量', default=0) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 06f0bfc7..4668e9d7 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -172,6 +172,7 @@ class SflogExpSerializer(CustomModelSerializer): class WMaterialSerializer(CustomModelSerializer): material_ = MaterialSimpleSerializer(source='material', read_only=True) + supplier_name = serializers.CharField(source='supplier.name', read_only=True) material_name = serializers.StringRelatedField( source='material', read_only=True) mgroup_name = serializers.StringRelatedField(source='mgroup.name', read_only=True) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index f12122b7..0d31384f 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -204,6 +204,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): belong_dept = mgroup.belong_dept material_out = mlog.material_out material_in = mlog.material_in + supplier = mlog.supplier # 外协 if material_in: # 需要进行车间库存管理 m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False) if m_ins.exists(): @@ -271,6 +272,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): wm.count = wm.count + mo_count wm.count_eweight = mo_count_eweight wm.update_by = user + if supplier is not None: + wm.supplier = supplier wm.save() mlog.submit_time = now diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 99bd2794..e8d2ea34 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -112,7 +112,7 @@ class WMaterialViewSet(ListModelMixin, CustomGenericViewSet): perms_map = {'get': '*'} queryset = WMaterial.objects.filter(count__gt=0) serializer_class = WMaterialSerializer - select_related_fields = ['material', 'belong_dept', 'material__process'] + select_related_fields = ['material', 'belong_dept', 'material__process', 'supplier'] search_fields = ['material__name', 'material__number', 'material__specification', 'batch', 'material__model'] filterset_class = WMaterialFilter From 78dc923305e1ab06ff980410fca26330457927b2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 30 Aug 2024 13:31:37 +0800 Subject: [PATCH 015/106] =?UTF-8?q?fix:=20=E6=97=A5=E5=BF=97=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E7=9A=84=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index e8d2ea34..7e0ccd07 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -209,11 +209,11 @@ class MlogViewSet(CustomModelViewSet): if ins.mtask and ins.mtask.state == Mtask.MTASK_STOP: raise ParseError('该任务已停止!') if ins.fill_way == Mlog.MLOG_STEP: - if not Mlogb.objects.filter(material_out__isnull=False).exists(): + if not Mlogb.objects.filter(material_out__isnull=False, mlog=ins).exists(): raise ParseError('该日志未指定产出!') - if not Mlogb.objects.filter(material_in__isnull=False).exists(): + if not Mlogb.objects.filter(material_in__isnull=False, mlog=ins).exists(): raise ParseError('该日志未指定消耗!') - if Mlogb.objects.filter(material_out__isnull=False, count_real=0).exists(): + if Mlogb.objects.filter(material_out__isnull=False, count_real=0, mlog=ins).exists(): raise ParseError('产出数量不能为0!') with transaction.atomic(): mlog_submit(ins, self.request.user, now) From cff14fa0423aed2f314bf073ad80dffecf252194 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 30 Aug 2024 13:36:53 +0800 Subject: [PATCH 016/106] =?UTF-8?q?feat:=20ftestwork=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E6=8A=BD=E6=A3=80=E5=90=88=E6=A0=BC=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0022_ftestwork_count_sampling_ok.py | 18 ++++++++++++++++++ apps/qm/models.py | 3 +++ 2 files changed, 21 insertions(+) create mode 100644 apps/qm/migrations/0022_ftestwork_count_sampling_ok.py diff --git a/apps/qm/migrations/0022_ftestwork_count_sampling_ok.py b/apps/qm/migrations/0022_ftestwork_count_sampling_ok.py new file mode 100644 index 00000000..8f9bac26 --- /dev/null +++ b/apps/qm/migrations/0022_ftestwork_count_sampling_ok.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2024-08-30 05:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0021_ftestwork_mb'), + ] + + operations = [ + migrations.AddField( + model_name='ftestwork', + name='count_sampling_ok', + field=models.IntegerField(default=0, verbose_name='抽检合格数量'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index 1d0944f9..53766f9f 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -56,6 +56,8 @@ class NotOkOption(models.TextChoices): z = "z", _("脏") zhg = "zhg", _("准合格") yz = "yz", _("圆准") + + jgqbl = "jgqbl", _("加工前不良") qt = "qt", _("其它") @@ -117,6 +119,7 @@ class FtestWork(CommonBDModel): batch = models.CharField('生产批次', max_length=50) count = models.IntegerField('检验数量') count_sampling = models.IntegerField('抽检数量', default=0) + count_sampling_ok = models.IntegerField('抽检合格数量', default=0) count_ok = models.IntegerField('合格数量', default=0) count_notok = models.IntegerField('不合格数量', default=0) count_notok_json = models.JSONField('不合格项数量统计', default=dict, null=False, blank=True) From 91add9ec1d6defb5d1bd9552c10338303d742ca3 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 2 Sep 2024 14:17:52 +0800 Subject: [PATCH 017/106] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=8A=A0?= =?UTF-8?q?=E5=B7=A5=E5=89=8D=E4=B8=8D=E8=89=AF=E7=9A=84=E4=B8=8D=E5=90=88?= =?UTF-8?q?=E6=A0=BC=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0064_auto_20240902_1411.py | 23 +++++++++++++++++++ apps/wpm/models.py | 2 ++ 2 files changed, 25 insertions(+) create mode 100644 apps/wpm/migrations/0064_auto_20240902_1411.py diff --git a/apps/wpm/migrations/0064_auto_20240902_1411.py b/apps/wpm/migrations/0064_auto_20240902_1411.py new file mode 100644 index 00000000..f3ca18c4 --- /dev/null +++ b/apps/wpm/migrations/0064_auto_20240902_1411.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.12 on 2024-09-02 06:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0063_wmaterial_supplier'), + ] + + operations = [ + migrations.AddField( + model_name='mlog', + name='count_n_jgqbl', + field=models.PositiveIntegerField(default=0, verbose_name='加工前不良'), + ), + migrations.AddField( + model_name='mlogb', + name='count_n_jgqbl', + field=models.PositiveIntegerField(default=0, verbose_name='加工前不良'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 4d2f3026..7bb66431 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -155,6 +155,7 @@ class Mlog(CommonADModel): count_notok = models.PositiveIntegerField('不合格数', default=0) count_break_t = models.PositiveIntegerField('检验碎料数', default=0) + count_n_jgqbl = models.PositiveIntegerField('加工前不良', default=0) count_n_zw = models.PositiveIntegerField('炸纹', default=0) count_n_tw = models.PositiveIntegerField('条纹', default=0) count_n_qp = models.PositiveIntegerField('气泡', default=0) @@ -246,6 +247,7 @@ class Mlogb(BaseModel): count_ok = models.PositiveIntegerField('合格数量', default=0) count_notok = models.PositiveIntegerField('不合格数', default=0) + count_n_jgqbl = models.PositiveIntegerField('加工前不良', default=0) # 添加不合格字段后需要更改cal_mlog_count_from_mlogb count_n_hs = models.PositiveIntegerField('划伤', default=0) count_n_qp = models.PositiveIntegerField('气泡', default=0) From 40b012b9625def5efe7218cf1135f3b2e019894e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 2 Sep 2024 15:27:38 +0800 Subject: [PATCH 018/106] =?UTF-8?q?feat:=20=E5=8A=A0=E5=B7=A5=E5=89=8D?= =?UTF-8?q?=E4=B8=8D=E8=89=AF=E7=9A=84=E6=97=A5=E5=BF=97=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E5=92=8C=E6=92=A4=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 43 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 0d31384f..d8f9ada3 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -208,7 +208,12 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): if material_in: # 需要进行车间库存管理 m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False) if m_ins.exists(): - m_ins_list = [(mi.material_in, mi.batch, mi.count_use, mi.wm_in) for mi in m_ins.all()] + m_ins_list = [] + m_ins_bl_list = [] + for mi in m_ins.all(): + m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi.wm_in)) + if mi.count_n_jgqbl > 0: + m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_n_jgqbl)) else: m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in)] for mi in m_ins_list: @@ -239,6 +244,20 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): wm.count = wm.count - mi_count wm.update_by = user wm.save() + # 针对加工前不良的暂时额外处理 + for item in m_ins_bl_list: + material, batch, count_n_jgqbl = item + if count_n_jgqbl> 0: + lookup = {'batch': batch, 'material': material, 'mgroup': mgroup, 'notok_sign': 'jgqbl', 'state': WMaterial.WM_NOTOK} + wm, is_create = WMaterial.objects.get_or_create(**lookup, defaults={**lookup, "belong_dept": belong_dept}) + wm.count = wm.count + item.count_n_jgqbl + if is_create: + wm.create_by = user + else: + wm.update_by = user + wm.save() + + if material_out: # 需要入车间库存 into_wm_mgroup = material_out.process.into_wm_mgroup if material_out.process else False need_store_notok = material_out.process.store_notok if material_out.process else False @@ -302,7 +321,12 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): into_wm_mgroup = material_in.process.into_wm_mgroup if material_in.process else False m_ins = Mlogb.objects.filter(mlog=mlog, material_in__isnull=False) if m_ins.exists(): - m_ins_list = [(mi.material_in, mi.batch, mi.count_use, mi.wm_in) for mi in m_ins.all()] + m_ins_list = [] + m_ins_bl_list = [] + for mi in m_ins.all(): + m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi.wm_in)) + if mi.count_n_jgqbl > 0: + m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_n_jgqbl)) else: m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in)] for mi in m_ins_list: @@ -324,6 +348,21 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): wm.count = wm.count + mi_count wm.update_by = user wm.save() + # 针对加工前不良的暂时额外处理 + for item in m_ins_bl_list: + material, batch, count_n_jgqbl = item + if count_n_jgqbl> 0: + lookup = {'batch': batch, 'material': material, 'mgroup': mgroup, 'notok_sign': 'jgqbl', 'state': WMaterial.WM_NOTOK} + wm, is_create = WMaterial.objects.get_or_create(**lookup, defaults={**lookup, "belong_dept": belong_dept}) + wm.count = wm.count - item.count_n_jgqbl + if wm.count < 0: + raise ParseError('加工前不良数量大于库存量') + if is_create: + wm.create_by = user + else: + wm.update_by = user + wm.save() + if material_out: # 产物退回 # 有多个产物的情况 # 需要考虑不合格品退回的情况 From fc2195eba1f2fe0fe1173cc8901a3657dc5a777e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 2 Sep 2024 15:29:41 +0800 Subject: [PATCH 019/106] =?UTF-8?q?feat:=20ftestwork=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E6=9B=B4=E6=96=B0=E5=BA=93=E5=AD=98=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0023_ftestwork_need_update_wm.py | 18 +++ apps/qm/models.py | 1 + apps/qm/serializers.py | 2 +- apps/qm/services.py | 119 +++++++++--------- 4 files changed, 80 insertions(+), 60 deletions(-) create mode 100644 apps/qm/migrations/0023_ftestwork_need_update_wm.py diff --git a/apps/qm/migrations/0023_ftestwork_need_update_wm.py b/apps/qm/migrations/0023_ftestwork_need_update_wm.py new file mode 100644 index 00000000..db68613e --- /dev/null +++ b/apps/qm/migrations/0023_ftestwork_need_update_wm.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2024-09-02 07:27 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0022_ftestwork_count_sampling_ok'), + ] + + operations = [ + migrations.AddField( + model_name='ftestwork', + name='need_update_wm', + field=models.BooleanField(default=True, verbose_name='是否更新车间库存'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index 53766f9f..3501ae2e 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -122,6 +122,7 @@ class FtestWork(CommonBDModel): count_sampling_ok = models.IntegerField('抽检合格数量', default=0) count_ok = models.IntegerField('合格数量', default=0) count_notok = models.IntegerField('不合格数量', default=0) + need_update_wm = models.BooleanField('是否更新车间库存', default=True) count_notok_json = models.JSONField('不合格项数量统计', default=dict, null=False, blank=True) test_user = models.ForeignKey( User, verbose_name='操作人', on_delete=models.CASCADE, related_name='ftestwork_test_user', null=True, blank=True) diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index 47e1561b..b756b63b 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -63,7 +63,7 @@ class QuaStatUpdateSerializer(CustomModelSerializer): class FtestWorkCreateUpdateSerializer(CustomModelSerializer): class Meta: model = FtestWork - fields = ['id', 'wm', 'mb', 'type', 'type2', 'test_date', 'count', 'count_sampling', 'count_ok', 'count_notok', 'count_notok_json', 'test_user'] + fields = ['id', 'wm', 'mb', 'type', 'type2', 'test_date', 'count', 'count_sampling', 'count_ok', 'count_notok', 'count_notok_json', 'test_user', 'need_update_wm'] extra_kwargs = {'test_user': {'required': True}, 'type': {'required': True}} def validate(self, attrs): diff --git a/apps/qm/services.py b/apps/qm/services.py index 2a107090..e984855b 100644 --- a/apps/qm/services.py +++ b/apps/qm/services.py @@ -7,67 +7,68 @@ from django.utils import timezone def ftestwork_submit(ins:FtestWork, user: User): wm:WMaterial = ins.wm - if wm.state == WMaterial.WM_TEST: - # 更新对应的车间库存 - wm.count = wm.count - ins.count - if wm.count >= 0: - # 已检测的数量 - wm.count_xtest = wm.count_xtest + ins.count - wm.save() - else: - raise ParseError("超过待检数量") - # 生成合格的 - count_ok = ins.count_ok - if count_ok > 0: - wm, new_create = WMaterial.objects.get_or_create( - material=wm.material, - batch=wm.batch, - mgroup=wm.mgroup, - belong_dept=wm.belong_dept, - state=WMaterial.WM_OK, - defaults={ - 'count': count_ok, - 'material': wm.material, - 'batch': wm.batch, - 'mgroup': wm.mgroup, - 'belong_dept': wm.belong_dept, - } - ) - if not new_create: - wm.count = wm.count + count_ok + if ins.need_update_wm: + if wm.state == WMaterial.WM_TEST: + # 更新对应的车间库存 + wm.count = wm.count - ins.count + if wm.count >= 0: + # 已检测的数量 + wm.count_xtest = wm.count_xtest + ins.count wm.save() - else: - wm.count = wm.count - ins.count_notok - if wm.count >= 0: - wm.save() + else: + raise ParseError("超过待检数量") + # 生成合格的 + count_ok = ins.count_ok + if count_ok > 0: + wm, new_create = WMaterial.objects.get_or_create( + material=wm.material, + batch=wm.batch, + mgroup=wm.mgroup, + belong_dept=wm.belong_dept, + state=WMaterial.WM_OK, + defaults={ + 'count': count_ok, + 'material': wm.material, + 'batch': wm.batch, + 'mgroup': wm.mgroup, + 'belong_dept': wm.belong_dept, + } + ) + if not new_create: + wm.count = wm.count + count_ok + wm.save() else: - raise ParseError("不合格数不可大于批次数量") - - # 生成不合格的 - count_notok_json = ins.count_notok_json - for k, v in count_notok_json.items(): - if v > 0: - notok_sign = k.replace('count_n_', '') - wm_n, new_create = WMaterial.objects.get_or_create( - material=wm.material, - batch=wm.batch, - mgroup=wm.mgroup, - belong_dept=wm.belong_dept, - notok_sign=notok_sign, - state=WMaterial.WM_NOTOK, - defaults={ - 'count': v, - 'material': wm.material, - 'batch': wm.batch, - 'mgroup': wm.mgroup, - 'belong_dept': wm.belong_dept, - 'notok_sign': notok_sign, - 'state': WMaterial.WM_NOTOK, - } - ) - if not new_create: - wm_n.count = wm_n.count + v - wm_n.save() + wm.count = wm.count - ins.count_notok + if wm.count >= 0: + wm.save() + else: + raise ParseError("不合格数不可大于批次数量") + + # 生成不合格的 + count_notok_json = ins.count_notok_json + for k, v in count_notok_json.items(): + if v > 0: + notok_sign = k.replace('count_n_', '') + wm_n, new_create = WMaterial.objects.get_or_create( + material=wm.material, + batch=wm.batch, + mgroup=wm.mgroup, + belong_dept=wm.belong_dept, + notok_sign=notok_sign, + state=WMaterial.WM_NOTOK, + defaults={ + 'count': v, + 'material': wm.material, + 'batch': wm.batch, + 'mgroup': wm.mgroup, + 'belong_dept': wm.belong_dept, + 'notok_sign': notok_sign, + 'state': WMaterial.WM_NOTOK, + } + ) + if not new_create: + wm_n.count = wm_n.count + v + wm_n.save() ins.submit_user = user ins.submit_time = timezone.now() ins.save() \ No newline at end of file From 65c1c8aa40332ceb8a0c941646d3cd8dda8796ff Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 2 Sep 2024 15:51:34 +0800 Subject: [PATCH 020/106] fix: mlogb update serializer --- apps/wpm/serializers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 4668e9d7..e71cce64 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -379,7 +379,7 @@ class MlogChangeSerializer(CustomModelSerializer): class MlogbInSerializer(CustomModelSerializer): class Meta: model = Mlogb - fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use'] + fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_n_jqgbl', 'count_break'] extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': True}, 'wm_in': {'required': True}} def validate(self, attrs): @@ -417,13 +417,13 @@ class MlogbInSerializer(CustomModelSerializer): class MlogbInUpdateSerializer(CustomModelSerializer): class Meta: model = Mlogb - fields = ['id', 'count_use', 'count_break'] + fields = ['id', 'count_use', 'count_break', 'count_n_jqgbl'] class MlogbOutUpdateSerializer(CustomModelSerializer): class Meta: model = Mlogb fields = "__all__" - read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break'] + read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break', 'count_n_jqgbl'] def validate(self, attrs): count_notok = 0 From b3e527e5a60c3c5beaec4427f135ad03a9e1bccc Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 2 Sep 2024 16:58:16 +0800 Subject: [PATCH 021/106] =?UTF-8?q?fix:=20count=5Fn=5Fjgqbl=20=E5=AD=97?= =?UTF-8?q?=E7=AC=A6=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index e71cce64..0e79a595 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -379,7 +379,7 @@ class MlogChangeSerializer(CustomModelSerializer): class MlogbInSerializer(CustomModelSerializer): class Meta: model = Mlogb - fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_n_jqgbl', 'count_break'] + fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_n_jgqbl', 'count_break'] extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': True}, 'wm_in': {'required': True}} def validate(self, attrs): @@ -423,7 +423,7 @@ class MlogbOutUpdateSerializer(CustomModelSerializer): class Meta: model = Mlogb fields = "__all__" - read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break', 'count_n_jqgbl'] + read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break', 'count_n_jgqbl'] def validate(self, attrs): count_notok = 0 From 2a8254b5812f243407ff34d3dd66facc545e4dad Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 2 Sep 2024 17:04:59 +0800 Subject: [PATCH 022/106] =?UTF-8?q?feat:=20process=E6=B7=BB=E5=8A=A0mlog?= =?UTF-8?q?=5Fneed=5Fticket=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0040_process_mlog_need_ticket.py | 18 ++++++++++++++++++ apps/mtm/models.py | 1 + 2 files changed, 19 insertions(+) create mode 100644 apps/mtm/migrations/0040_process_mlog_need_ticket.py diff --git a/apps/mtm/migrations/0040_process_mlog_need_ticket.py b/apps/mtm/migrations/0040_process_mlog_need_ticket.py new file mode 100644 index 00000000..1549d30a --- /dev/null +++ b/apps/mtm/migrations/0040_process_mlog_need_ticket.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2024-09-02 09:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0039_alter_material_unit_price'), + ] + + operations = [ + migrations.AddField( + model_name='process', + name='mlog_need_ticket', + field=models.BooleanField(default=False, verbose_name='日志提交是否需要审批'), + ), + ] diff --git a/apps/mtm/models.py b/apps/mtm/models.py index 37b47f7e..4e2f3d49 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -18,6 +18,7 @@ class Process(CommonBModel): into_wm_mgroup = models.BooleanField('交接到工段', default=False) store_notok = models.BooleanField('不合格品是否入库', default=False) batch_append_equip = models.BooleanField('批号追加设备', default=False) + mlog_need_ticket = models.BooleanField('日志提交是否需要审批', default=False) class Meta: verbose_name = '工序' From 6a573dd4ddcc92651228daf210001605c11ce0af Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 09:10:28 +0800 Subject: [PATCH 023/106] =?UTF-8?q?feat:=20mlog=E7=BB=8F=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E5=90=8E=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0065_auto_20240903_0904.py | 25 +++++++++++ apps/wpm/models.py | 6 ++- apps/wpm/serializers.py | 2 +- apps/wpm/services.py | 42 +++++++++++++++++-- apps/wpm/views.py | 19 ++++----- 5 files changed, 77 insertions(+), 17 deletions(-) create mode 100644 apps/wpm/migrations/0065_auto_20240903_0904.py diff --git a/apps/wpm/migrations/0065_auto_20240903_0904.py b/apps/wpm/migrations/0065_auto_20240903_0904.py new file mode 100644 index 00000000..ab6836dc --- /dev/null +++ b/apps/wpm/migrations/0065_auto_20240903_0904.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.12 on 2024-09-03 01:04 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wf', '0002_alter_state_filter_dept'), + ('wpm', '0064_auto_20240902_1411'), + ] + + operations = [ + migrations.AddField( + model_name='mlog', + name='oinfo_json', + field=models.JSONField(blank=True, default=dict, verbose_name='其他信息'), + ), + migrations.AddField( + model_name='mlog', + name='ticket', + field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mlog_ticket', to='wf.ticket', verbose_name='关联工单'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 7bb66431..7085bdcb 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -193,8 +193,6 @@ class Mlog(CommonADModel): count_n_yd = models.PositiveIntegerField('圆度', default=0) count_n_txd = models.PositiveIntegerField('同心度', default=0) count_n_hd = models.PositiveIntegerField('厚度', default=0) - - count_n_qt = models.PositiveIntegerField('其他', default=0) handle_date = models.DateField('操作日期', null=True, blank=True) @@ -214,6 +212,10 @@ class Mlog(CommonADModel): submit_user = models.ForeignKey( User, verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_submit_user') + oinfo_json = models.JSONField('其他信息', default=dict, blank=True) + ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', + on_delete=models.SET_NULL, related_name='mlog_ticket', null=True, blank=True, db_constraint=False) + @property def mlogb(self): return Mlogb.objects.filter(mlog=self).exclude(material_out=None) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 0e79a595..d2c815ff 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -368,7 +368,7 @@ class MlogInitSerializer(CustomModelSerializer): class MlogChangeSerializer(CustomModelSerializer): class Meta: model = Mlog - fields = ['id', 'work_end_time', 'handle_user', 'note'] + fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json'] def validate(self, attrs): if attrs.get('work_end_time', None): diff --git a/apps/wpm/services.py b/apps/wpm/services.py index d8f9ada3..1f016479 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -4,7 +4,6 @@ from django.core.cache import cache from django.db.models import Sum from django.utils import timezone from typing import Union -from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned from rest_framework.exceptions import ParseError @@ -13,9 +12,11 @@ from apps.inm.models import MIO, MIOItem, MIOItemA from apps.pm.models import Mtask from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack -from .models import SfLog, SfLogExp, WMaterial, Mlog, Mlogb, Handover -from apps.mtm.models import Process +from .models import SfLog, WMaterial, Mlog, Mlogb, Handover from apps.mtm.services import cal_material_count +from apps.wf.models import Ticket +from django.db import transaction +from apps.utils.thread import MyThread def find_material_can_change(material: Material, mgroup_to: Mgroup): """ @@ -633,3 +634,38 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime handover.submit_user = user handover.submit_time = now handover.save() + +def mlog_submit_validate(ins: Mlog): + if ins.submit_time: + raise ParseError('该日志已提交!') + if ins.mtask and ins.mtask.state == Mtask.MTASK_STOP: + raise ParseError('该任务已停止!') + if ins.fill_way == Mlog.MLOG_STEP: + if not Mlogb.objects.filter(material_out__isnull=False, mlog=ins).exists(): + raise ParseError('该日志未指定产出!') + if not Mlogb.objects.filter(material_in__isnull=False, mlog=ins).exists(): + raise ParseError('该日志未指定消耗!') + if Mlogb.objects.filter(material_out__isnull=False, count_real=0, mlog=ins).exists(): + raise ParseError('产出数量不能为0!') + +def bind_mlog(ticket: Ticket, transition, new_ticket_data: dict): + ins = Mlog.objects.get(id=new_ticket_data['t_id']) + mlog_submit_validate(ins) # 校验是否可submit + ticket_data = ticket.ticket_data + ticket_data.update({ + 't_model': 'mlog', + 't_id': ins.id, + }) + ticket.ticket_data = ticket_data + ticket.create_by = ins.create_by + ticket.save() + if ins.ticket is None: + ins.ticket = ticket + ins.save() + +def mlog_audit_end(ticket: Ticket): + now = timezone.now() + ins = Mlog.objects.get(id=ticket.ticket_data['t_id']) + mlog_submit(ins, ticket.create_by, now) + MyThread(target=cal_mtask_progress_from_mlog,args=(ins,)).start() + MyThread(target=cal_material_count_from_mlog,args=(ins,)).start() diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 7e0ccd07..4ed5031c 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -25,6 +25,7 @@ from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, from .services import mlog_submit, update_mtask, handover_submit, mlog_revert, cal_material_count_from_mlog, cal_mtask_progress_from_mlog from apps.utils.thread import MyThread from apps.monitor.services import create_auditlog, delete_auditlog +from apps.wpm.services import mlog_submit_validate # Create your views here. @@ -204,17 +205,13 @@ class MlogViewSet(CustomModelViewSet): ins: Mlog = self.get_object() vdata_old = MlogSerializer(ins).data now = timezone.now() - if ins.submit_time: - raise ParseError('该日志已提交!') - if ins.mtask and ins.mtask.state == Mtask.MTASK_STOP: - raise ParseError('该任务已停止!') - if ins.fill_way == Mlog.MLOG_STEP: - if not Mlogb.objects.filter(material_out__isnull=False, mlog=ins).exists(): - raise ParseError('该日志未指定产出!') - if not Mlogb.objects.filter(material_in__isnull=False, mlog=ins).exists(): - raise ParseError('该日志未指定消耗!') - if Mlogb.objects.filter(material_out__isnull=False, count_real=0, mlog=ins).exists(): - raise ParseError('产出数量不能为0!') + if ins.ticket: + raise ParseError('该日志存在审批!') + else: + p: Process = ins.mgroup.process + if p.mlog_need_ticket: + raise ParseError('该日志需要审批!') + mlog_submit_validate(ins) with transaction.atomic(): mlog_submit(ins, self.request.user, now) vdata_new = MlogSerializer(ins).data From 89af31a38336f3fe3a393ebf12c104eb652b64b5 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 09:48:10 +0800 Subject: [PATCH 024/106] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0check=5Ftest?= =?UTF-8?q?=5Fwhen=5Fdo=5Fout=E9=85=8D=E7=BD=AE=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/serializers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/inm/serializers.py b/apps/inm/serializers.py index 9f497659..4e0ba42a 100644 --- a/apps/inm/serializers.py +++ b/apps/inm/serializers.py @@ -10,6 +10,7 @@ from apps.utils.serializers import CustomModelSerializer from .models import MIO, MaterialBatch, MIOItem, WareHouse, MIOItemA, MaterialBatchA from django.db import transaction +from server.settings import get_sysconfig class WareHourseSerializer(CustomModelSerializer): @@ -104,7 +105,9 @@ class MIOItemCreateSerializer(CustomModelSerializer): if mio.state != MIO.MIO_CREATE: raise ValidationError('出入库记录非创建中不可新增') # 生产领料要校验是否进行检验 - if mio.type == MIO.MIO_TYPE_DO_OUT: + # 某些客户此处无需校验 + check_test_when_do_out = get_sysconfig('mes.check_test_when_do_out', True) + if check_test_when_do_out and mio.type == MIO.MIO_TYPE_DO_OUT: mis = MIOItem.objects.filter(batch=batch, material=material, mio__type__in=[MIO.MIO_TYPE_PUR_IN, MIO.MIO_TYPE_DO_IN, MIO.MIO_TYPE_OTHER_IN]) if mis.exists() and (not mis.exclude(test_date=None).exists()): raise ValidationError('该批次的物料未经检验') From 3c997704777c6c019074985e7dbc6f48583e5a39 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 09:50:43 +0800 Subject: [PATCH 025/106] =?UTF-8?q?feat:=20base=20get=5Fsysconfig=E5=8F=AF?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E9=BB=98=E8=AE=A4=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/settings.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/server/settings.py b/server/settings.py index 92604674..d6701e6a 100755 --- a/server/settings.py +++ b/server/settings.py @@ -341,7 +341,7 @@ LOGGING = { ##### 加载客户可自定义配置并提供操作方法 ##### SYS_JSON_PATH = os.path.join(BASE_DIR, 'server/conf.json') -def get_sysconfig(key='', reload=False): +def get_sysconfig(key='', default='raise_error', reload=False): """获取系统配置可指定key字符串 """ config = cache.get('system_config', None) @@ -355,7 +355,13 @@ def get_sysconfig(key='', reload=False): if key: k_l = key.split('.') for k in k_l: - config = config[k] + try: + config = config[k] + except KeyError: + if default == 'raise_error': + raise + else: + return default return config From 31f8f002aa31bc82f10bc1d5f08b9e13f05a08a7 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 10:25:59 +0800 Subject: [PATCH 026/106] =?UTF-8?q?feat:=20mlog=20=E5=A2=9E=E5=8A=A0ticket?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9D=A1=E4=BB=B6?= 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 d2c815ff..ed3e21c0 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -17,6 +17,7 @@ from django.utils import timezone from django.core.cache import cache from django.utils.timezone import localdate from apps.qm.models import NotOkOption +from apps.wf.serializers import TicketSimpleSerializer class OtherLogSerializer(CustomModelSerializer): @@ -261,6 +262,7 @@ class MlogSerializer(CustomModelSerializer): source='handle_users', many=True, read_only=True) equipments_name = serializers.StringRelatedField( source='equipments', read_only=True, many=True) + ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) class Meta: model = Mlog diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 4ed5031c..ec2fd45a 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -142,7 +142,7 @@ class MlogViewSet(CustomModelViewSet): queryset = Mlog.objects.all() serializer_class = MlogSerializer select_related_fields = ['create_by', 'update_by', 'mtask', - 'handle_user', 'handle_user_2', 'equipment', 'equipment_2', 'material_in', 'material_out', 'supplier'] + 'handle_user', 'handle_user_2', 'equipment', 'equipment_2', 'material_in', 'material_out', 'supplier', 'ticket'] prefetch_related_fields = ['handle_users', 'material_outs', 'b_mlog', 'equipments'] filterset_class = MlogFilter From 0148efba62af93c71b2fd6b664346a304f1758e8 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 10:58:33 +0800 Subject: [PATCH 027/106] =?UTF-8?q?feat:=20process=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=B8=AD=E9=97=B4=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/mtm/admin.py | 2 +- .../mtm/migrations/0041_process_mstate_json.py | 18 ++++++++++++++++++ apps/mtm/models.py | 1 + apps/wpm/serializers.py | 1 + apps/wpm/views.py | 4 +++- 5 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 apps/mtm/migrations/0041_process_mstate_json.py diff --git a/apps/mtm/admin.py b/apps/mtm/admin.py index 2aec3530..5de10265 100644 --- a/apps/mtm/admin.py +++ b/apps/mtm/admin.py @@ -5,7 +5,7 @@ from apps.mtm.models import Material, Shift, Mgroup, Process @admin.register(Process) class ProcessAdmin(admin.ModelAdmin): - list_display = ('id', 'name', 'cate', 'sort', 'into_wm_mgroup', 'store_notok', 'batch_append_equip') + list_display = ('id', 'name', 'cate', 'sort', 'into_wm_mgroup', 'store_notok', 'batch_append_equip', 'mlog_need_ticket') @admin.register(Material) diff --git a/apps/mtm/migrations/0041_process_mstate_json.py b/apps/mtm/migrations/0041_process_mstate_json.py new file mode 100644 index 00000000..84f21c3b --- /dev/null +++ b/apps/mtm/migrations/0041_process_mstate_json.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2024-09-03 02:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0040_process_mlog_need_ticket'), + ] + + operations = [ + migrations.AddField( + model_name='process', + name='mstate_json', + field=models.JSONField(blank=True, default=list, verbose_name='中间状态'), + ), + ] diff --git a/apps/mtm/models.py b/apps/mtm/models.py index 4e2f3d49..5998d83a 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -19,6 +19,7 @@ class Process(CommonBModel): store_notok = models.BooleanField('不合格品是否入库', default=False) batch_append_equip = models.BooleanField('批号追加设备', default=False) mlog_need_ticket = models.BooleanField('日志提交是否需要审批', default=False) + mstate_json = models.JSONField('中间状态', default=list, blank=True) class Meta: verbose_name = '工序' diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index ed3e21c0..b40352cc 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -213,6 +213,7 @@ class MlogbDetailSerializer(CustomModelSerializer): fields = '__all__' class MlogSerializer(CustomModelSerializer): + mstate_json = serializers.JSONField(source='mgroup.process.mstate_json', read_only=True) supplier_name = serializers.CharField(source='supplier.name', read_only=True) belong_dept = serializers.CharField( source='mgroup.belong_dept.id', read_only=True) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index ec2fd45a..6365295e 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -142,7 +142,9 @@ class MlogViewSet(CustomModelViewSet): queryset = Mlog.objects.all() serializer_class = MlogSerializer select_related_fields = ['create_by', 'update_by', 'mtask', - 'handle_user', 'handle_user_2', 'equipment', 'equipment_2', 'material_in', 'material_out', 'supplier', 'ticket'] + 'handle_user', 'handle_user_2', 'equipment', + 'equipment_2', 'material_in', 'material_out', + 'supplier', 'ticket', 'mgroup__process'] prefetch_related_fields = ['handle_users', 'material_outs', 'b_mlog', 'equipments'] filterset_class = MlogFilter From bb311999e8f81762c4f51506d835bea7b3ead9f7 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 14:16:18 +0800 Subject: [PATCH 028/106] =?UTF-8?q?feat:=20mlogb=20=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E4=BB=A5=E8=AE=B0=E5=BD=95=E5=88=86=E5=B1=82?= =?UTF-8?q?=E6=A3=80=E9=AA=8C=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0066_auto_20240903_1401.py | 28 +++++++++++++++++++ apps/wpm/models.py | 3 ++ apps/wpm/serializers.py | 27 ++++++++++++++++-- 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 apps/wpm/migrations/0066_auto_20240903_1401.py diff --git a/apps/wpm/migrations/0066_auto_20240903_1401.py b/apps/wpm/migrations/0066_auto_20240903_1401.py new file mode 100644 index 00000000..98e1ff94 --- /dev/null +++ b/apps/wpm/migrations/0066_auto_20240903_1401.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.12 on 2024-09-03 06:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0065_auto_20240903_0904'), + ] + + operations = [ + migrations.AddField( + model_name='mlog', + name='test_file', + field=models.TextField(blank=True, null=True, verbose_name='检验文件'), + ), + migrations.AddField( + model_name='mlogb', + name='count_notok_json', + field=models.JSONField(blank=True, default=list, verbose_name='不合格情况'), + ), + migrations.AddField( + model_name='mlogb', + name='note', + field=models.TextField(blank=True, default='', verbose_name='备注'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 7085bdcb..9c91e58a 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -215,6 +215,7 @@ class Mlog(CommonADModel): oinfo_json = models.JSONField('其他信息', default=dict, blank=True) ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.SET_NULL, related_name='mlog_ticket', null=True, blank=True, db_constraint=False) + test_file = models.TextField('检验文件', null=True, blank=True) @property def mlogb(self): @@ -233,6 +234,7 @@ class Mlog(CommonADModel): class Mlogb(BaseModel): mlog = models.ForeignKey(Mlog, verbose_name='关联日志', on_delete=models.CASCADE, related_name='b_mlog') + note = models.TextField('备注', default='', blank=True) batch = models.CharField('批次号', max_length=50, null=True, blank=True) mtask = models.ForeignKey(Mtask, verbose_name='关联任务', on_delete=models.CASCADE, related_name='mlogb_mtask', null=True, blank=True) @@ -265,6 +267,7 @@ class Mlogb(BaseModel): count_n_txd = models.PositiveIntegerField('同心度', default=0) count_n_hd = models.PositiveIntegerField('厚度', default=0) count_n_qt = models.PositiveIntegerField('其他', default=0) + count_notok_json = models.JSONField('不合格情况', default=list, blank=True) class Handover(CommonADModel): """ diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index b40352cc..46fdf69e 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -371,7 +371,7 @@ class MlogInitSerializer(CustomModelSerializer): class MlogChangeSerializer(CustomModelSerializer): class Meta: model = Mlog - fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json'] + fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file'] def validate(self, attrs): if attrs.get('work_end_time', None): @@ -382,7 +382,7 @@ class MlogChangeSerializer(CustomModelSerializer): class MlogbInSerializer(CustomModelSerializer): class Meta: model = Mlogb - fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_n_jgqbl', 'count_break'] + fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_n_jgqbl', 'count_break', 'note'] extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': True}, 'wm_in': {'required': True}} def validate(self, attrs): @@ -420,7 +420,7 @@ class MlogbInSerializer(CustomModelSerializer): class MlogbInUpdateSerializer(CustomModelSerializer): class Meta: model = Mlogb - fields = ['id', 'count_use', 'count_break', 'count_n_jqgbl'] + fields = ['id', 'count_use', 'count_break', 'count_n_jgqbl', 'note'] class MlogbOutUpdateSerializer(CustomModelSerializer): class Meta: @@ -429,6 +429,27 @@ class MlogbOutUpdateSerializer(CustomModelSerializer): read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break', 'count_n_jgqbl'] def validate(self, attrs): + count_notok_json = attrs.get('count_notok_json', []) + # count_notok_json字段处理 + if count_notok_json: + # 先置0字段 + for i in attrs: + if 'count_n_' in i: + i = 0 + count_notok_dict = {} + for item in count_notok_json: + notok = item['notok'] + count = item['count'] + full_notok = f'count_n_{notok}' + if not hasattr(Mlogb, full_notok): + raise ValidationError(f'{notok}-该不合格项不存在') + if full_notok in count_notok_dict: + count_notok_dict[full_notok] = count_notok_dict[full_notok] + count + else: + count_notok_dict[full_notok] = count + for k, v in count_notok_dict.items(): + attrs[k] = v + count_notok = 0 for i in attrs: if 'count_n_' in i: From bc9a098cc8efe25b131aea829d4a467bbead3c29 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 14:51:23 +0800 Subject: [PATCH 029/106] =?UTF-8?q?feat:=20mtask=5Fsubmit=20=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=98=AF=E5=90=A6=E6=9C=89=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/services.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/pm/services.py b/apps/pm/services.py index a049102c..fabdfc30 100644 --- a/apps/pm/services.py +++ b/apps/pm/services.py @@ -311,6 +311,8 @@ class PmService: now = timezone.now() if mtask.state == Mtask.MTASK_ASSGINED: mlogs = Mlog.objects.filter(mtask=mtask)|Mlog.objects.filter(b_mlog__mtask=mtask) + if not mlogs.exists(): + raise ParseError('该任务没有日志') if mlogs.filter(submit_time__isnull=True).exists(): raise ParseError('存在未提交的日志') mtask.state = Mtask.MTASK_SUBMIT From 9fee0b52d5b59a659ac5505dc08a54dcaba74a47 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 16:41:51 +0800 Subject: [PATCH 030/106] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0mtaskb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/migrations/0020_mtaskb.py | 32 +++++++++++++++++++++++++++++++ apps/pm/models.py | 9 ++++++++- apps/pm/serializers.py | 16 +++++++++++++++- apps/pm/urls.py | 3 ++- apps/pm/views.py | 13 +++++++++++-- 5 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 apps/pm/migrations/0020_mtaskb.py diff --git a/apps/pm/migrations/0020_mtaskb.py b/apps/pm/migrations/0020_mtaskb.py new file mode 100644 index 00000000..bd319ecb --- /dev/null +++ b/apps/pm/migrations/0020_mtaskb.py @@ -0,0 +1,32 @@ +# Generated by Django 3.2.12 on 2024-09-03 08:38 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('pm', '0019_auto_20240703_1618'), + ] + + operations = [ + migrations.CreateModel( + name='Mtaskb', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('count', models.PositiveIntegerField(default=0, verbose_name='任务数')), + ('handle_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='mtaskb_handle_user', to=settings.AUTH_USER_MODEL, verbose_name='操作人')), + ('mtask', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='b_mtask', to='pm.mtask', verbose_name='关联任务')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/pm/models.py b/apps/pm/models.py index 391191e2..02e6c934 100644 --- a/apps/pm/models.py +++ b/apps/pm/models.py @@ -1,5 +1,5 @@ from django.db import models -from apps.utils.models import CommonADModel, CommonBDModel +from apps.utils.models import CommonADModel, CommonBDModel, BaseModel from apps.mtm.models import Material, Mgroup, RoutePack, Route # Create your models here. @@ -111,3 +111,10 @@ class Mtask(CommonADModel): def mlogs(self): from apps.wpm.models import Mlog return Mlog.objects.filter(mtask=self) + + +class Mtaskb(BaseModel): + mtask = models.ForeignKey(Mtask, verbose_name='关联任务', on_delete=models.CASCADE, related_name='b_mtask') + handle_user = models.ForeignKey( + 'system.user', verbose_name='操作人', on_delete=models.CASCADE, related_name='mtaskb_handle_user') + count = models.PositiveIntegerField('任务数', default=0) \ No newline at end of file diff --git a/apps/pm/serializers.py b/apps/pm/serializers.py index c0245fe7..8a6a5d8d 100644 --- a/apps/pm/serializers.py +++ b/apps/pm/serializers.py @@ -3,11 +3,12 @@ from rest_framework.exceptions import ValidationError, ParseError import math from apps.mtm.serializers import MaterialSimpleSerializer -from apps.pm.models import Mtask, Utask, SCHEDULE_TYPE +from apps.pm.models import Mtask, Utask, SCHEDULE_TYPE, Mtaskb from apps.sam.models import OrderItem from apps.utils.serializers import CustomModelSerializer from apps.system.models import Dept from apps.wpm.models import Mlog +from apps.utils.constants import EXCLUDE_FIELDS_BASE class UtaskSerializer(CustomModelSerializer): @@ -110,3 +111,16 @@ class MtaskAddInfoSerializer(CustomModelSerializer): class Meta: model = Mtask fields = ['peifen_kg'] + +class MtaskbSerializer(CustomModelSerializer): + handle_user_name = serializers.StringRelatedField( + source='handle_user.name', read_only=True) + class Meta: + model = Mtaskb + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS_BASE + +class MtaskbUpdateSerializer(CustomModelSerializer): + class Meta: + model = Mtaskb + fields = ['id', 'count'] \ No newline at end of file diff --git a/apps/pm/urls.py b/apps/pm/urls.py index b75e9f9e..082f7d3d 100644 --- a/apps/pm/urls.py +++ b/apps/pm/urls.py @@ -1,12 +1,13 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.pm.views import (MtaskViewSet, UtaskViewSet) +from apps.pm.views import (MtaskViewSet, UtaskViewSet, MtaskbViewSet) API_BASE_URL = 'api/pm/' HTML_BASE_URL = 'pm/' router = DefaultRouter() router.register('mtask', MtaskViewSet, basename='mtask') +router.register('mtaskb', MtaskbViewSet, basename='mtaskb') router.register('utask', UtaskViewSet, basename='utask') urlpatterns = [ path(API_BASE_URL, include(router.urls)), diff --git a/apps/pm/views.py b/apps/pm/views.py index eadc1cc8..4b06348a 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -8,9 +8,10 @@ from apps.utils.serializers import PkSerializer from apps.utils.viewsets import CustomModelViewSet from .filters import MtaskFilter, UtaskFilter -from .models import Mtask, Utask +from .models import Mtask, Utask, Mtaskb from .serializers import (MtaskSerializer, SchedueSerializer, UtaskSerializer, - MtaskDaySerializer, MtaskAddInfoSerializer, SchedueMtasksSerializer) + MtaskDaySerializer, MtaskAddInfoSerializer, + SchedueMtasksSerializer, MtaskbSerializer, MtaskbUpdateSerializer) from .services import PmService from django.utils import timezone @@ -204,3 +205,11 @@ class MtaskViewSet(CustomModelViewSet): sr.is_valid(raise_exception=True) sr.save() return Response() + + +class MtaskbViewSet(CustomModelViewSet): + queryset = Mtaskb.objects.all() + serializer_class = MtaskbSerializer + update_serializer_class = MtaskbUpdateSerializer + filterset_fields = {"mtask": ["exact"], "handle_user": ["exact"]} + ordering = ['id'] \ No newline at end of file From 044819815e9532d7aa2850bb6ec9b3f27644bb8c Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 3 Sep 2024 17:57:23 +0800 Subject: [PATCH 031/106] =?UTF-8?q?fix:=20cal=5Fmlog=5Fcount=5Ffrom=5Fmlog?= =?UTF-8?q?b=20=E7=BB=9F=E8=AE=A1bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 1f016479..5f56828a 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -433,7 +433,7 @@ def cal_mlog_count_from_mlogb(mlog: Mlog): "total_count_ok": Sum('count_ok'), "total_count_notok": Sum('count_notok'), } - f_names = [f.name for f in Mlogb._meta.fields if 'count_n' in f.name] + f_names = [f.name for f in Mlogb._meta.fields if 'count_n_' in f.name] for f in f_names: a_dict[f'total_{f}'] = Sum(f) mlogb_summary = Mlogb.objects.filter(mlog=mlog).aggregate( From 170f3db82440d556ad1a1d1339f16250126d9d0a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 09:04:37 +0800 Subject: [PATCH 032/106] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0fmlog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0067_auto_20240904_0903.py | 42 +++++++++++++++++++ apps/wpm/models.py | 7 ++++ apps/wpm/serializers.py | 17 +++++++- apps/wpm/urls.py | 4 +- apps/wpm/views.py | 22 ++++++++-- 5 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 apps/wpm/migrations/0067_auto_20240904_0903.py diff --git a/apps/wpm/migrations/0067_auto_20240904_0903.py b/apps/wpm/migrations/0067_auto_20240904_0903.py new file mode 100644 index 00000000..7b2a4520 --- /dev/null +++ b/apps/wpm/migrations/0067_auto_20240904_0903.py @@ -0,0 +1,42 @@ +# Generated by Django 3.2.12 on 2024-09-04 01:03 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0041_process_mstate_json'), + ('pm', '0020_mtaskb'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('wpm', '0066_auto_20240903_1401'), + ] + + operations = [ + migrations.CreateModel( + name='Fmlog', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('note', models.TextField(blank=True, default='', verbose_name='备注')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='fmlog_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('mgroup', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fmlog_mgroup', to='mtm.mgroup', verbose_name='工段')), + ('mtask', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fmlog_mtask', to='pm.mtask', verbose_name='任务')), + ('route', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.route', verbose_name='生产路线')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='fmlog_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='mlog', + name='fmlog', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='mlog_fmlog', to='wpm.fmlog', verbose_name='关联生产日志'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 9c91e58a..ea45c53f 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -107,6 +107,12 @@ class WMaterial(CommonBDModel): count_xtest = models.PositiveIntegerField('已检数量', null=True, blank=True) +class Fmlog(CommonADModel): + route = models.ForeignKey(Route, verbose_name='生产路线', on_delete=models.SET_NULL, null=True, blank=True) + mtask = models.ForeignKey(Mtask, verbose_name='任务', on_delete=models.CASCADE, related_name='fmlog_mtask') + mgroup = models.ForeignKey(Mgroup, verbose_name='工段', on_delete=models.CASCADE, related_name='fmlog_mgroup') + note = models.TextField('备注', default='', blank=True) + class Mlog(CommonADModel): """ 生产日志 @@ -116,6 +122,7 @@ class Mlog(CommonADModel): MLOG_STEP = 20 MTYPE_SELF = 10 MTYPE_OUT = 20 + fmlog = models.ForeignKey(Fmlog, verbose_name='关联生产日志', on_delete=models.SET_NULL, null=True, blank=True, related_name='mlog_fmlog') fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:一次填写;20:分步填写') mtype = models.PositiveSmallIntegerField('生产类型', default=10, help_text='10:自生产;20:外协生产', choices=((10, '自生产'), (20, '外协生产'))) supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 46fdf69e..42338ecc 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -4,7 +4,7 @@ from rest_framework import serializers from rest_framework.exceptions import ValidationError, ParseError from datetime import datetime -from .models import SfLog, StLog, SfLogExp, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog +from .models import SfLog, StLog, SfLogExp, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog, Fmlog from apps.system.models import Dept, User from apps.system.serializers import UserSimpleSerializer from apps.pm.models import Mtask @@ -597,3 +597,18 @@ class AttLogSerializer(CustomModelSerializer): class Meta: model = AttLog fields = '__all__' + + +class FmlogSerializer(CustomModelSerializer): + routepack_name = serializers.CharField( + source='route.routepack.name', read_only=True) + mtask_number = serializers.CharField(source='mtask.number', read_only=True) + class Meta: + model = Fmlog + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + +class FmlogUpdateSerializer(CustomModelSerializer): + class Meta: + model = Fmlog + fields = ['id', 'note'] \ No newline at end of file diff --git a/apps/wpm/urls.py b/apps/wpm/urls.py index 005f4377..3de12711 100644 --- a/apps/wpm/urls.py +++ b/apps/wpm/urls.py @@ -3,7 +3,8 @@ from rest_framework.routers import DefaultRouter from apps.wpm.views import (SfLogViewSet, StLogViewSet, SfLogExpViewSet, WMaterialViewSet, MlogViewSet, HandoverViewSet, - AttlogViewSet, OtherLogViewSet, MlogbViewSet, MlogbInViewSet, MlogbOutViewSet) + AttlogViewSet, OtherLogViewSet, MlogbViewSet, MlogbInViewSet, + MlogbOutViewSet, FmlogViewSet) API_BASE_URL = 'api/wpm/' @@ -14,6 +15,7 @@ router.register('sflog', SfLogViewSet, basename='sflog') router.register('stlog', StLogViewSet, basename='stlog') router.register('sflogexp', SfLogExpViewSet, basename='sflogexp') router.register('wmaterial', WMaterialViewSet, basename='wmaterial') +router.register('fmlog', FmlogViewSet, basename='fmlog') router.register('mlog', MlogViewSet, basename='mlog') router.register('mlogb', MlogbViewSet) router.register('mlogb/in', MlogbInViewSet) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 6365295e..525951b2 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -16,12 +16,13 @@ from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.utils.mixins import BulkCreateModelMixin from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter -from .models import SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog +from .models import SfLog, SfLogExp, StLog, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog, Fmlog from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, WMaterialSerializer, MlogRevertSerializer, MlogSerializer, MlogRelatedSerializer, DeptBatchSerializer, HandoverSerializer, HandoverUpdateSerializer, GenHandoverSerializer, GenHandoverWmSerializer, MlogAnaSerializer, AttLogSerializer, OtherLogSerializer, MlogInitSerializer, MlogChangeSerializer, - MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer, MlogbOutUpdateSerializer) + MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer, + MlogbOutUpdateSerializer, FmlogSerializer, FmlogUpdateSerializer) from .services import mlog_submit, update_mtask, handover_submit, mlog_revert, cal_material_count_from_mlog, cal_mtask_progress_from_mlog from apps.utils.thread import MyThread from apps.monitor.services import create_auditlog, delete_auditlog @@ -497,4 +498,19 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust class MlogbOutViewSet(UpdateModelMixin, CustomGenericViewSet): perms_map = {"put": "mlog.update"} queryset = Mlogb.objects.filter(material_out__isnull=False) - serializer_class = MlogbOutUpdateSerializer \ No newline at end of file + serializer_class = MlogbOutUpdateSerializer + + +class FmlogViewSet(CustomModelViewSet): + perms_map = {'get': '*', 'post': 'mlog.create', 'put': 'mlog.update', 'delete': 'mlog.delete'} + queryset = Fmlog.objects.all() + serializer_class = FmlogSerializer + update_serializer_class = FmlogUpdateSerializer + filterset_fields = ['mtask', 'mgroup', 'route'] + select_related_fields = ['mtask', 'mgroup', 'route', 'route__routepack'] + + def destroy(self, request, *args, **kwargs): + ins = self.get_object() + if Mlog.objects.filter(fmlog=ins).exists(): + raise ParseError('因存在二级日志不可删除') + return super().destroy(request, *args, **kwargs) \ No newline at end of file From 233591728aadcfcab748329c9895c9bb80eefbe8 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 09:13:26 +0800 Subject: [PATCH 033/106] =?UTF-8?q?feat:=20fmlog=E5=88=9B=E5=BB=BA?= =?UTF-8?q?=E6=97=B6=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 42338ecc..cab75060 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -607,6 +607,15 @@ class FmlogSerializer(CustomModelSerializer): model = Fmlog fields = '__all__' read_only_fields = EXCLUDE_FIELDS + + def validate(self, attrs): + route: Route = attrs['route'] + mtask: Mtask = attrs['mtask'] + mgroup: Mgroup = attrs['mgroup'] + if route.process != mgroup.process: + raise ParseError('工序不匹配') + if mtask.mgroup != mgroup: + raise ParseError('工段不匹配') class FmlogUpdateSerializer(CustomModelSerializer): class Meta: From 9ca66782b9b98dc295c5c7f865851540f6c4992f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 10:22:38 +0800 Subject: [PATCH 034/106] =?UTF-8?q?fix:=20FtestWorkCreateUpdate=20?= =?UTF-8?q?=E7=BC=BA=E5=B0=91count=5Fsampling=5Fok?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index b756b63b..b5f941c2 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -63,7 +63,7 @@ class QuaStatUpdateSerializer(CustomModelSerializer): class FtestWorkCreateUpdateSerializer(CustomModelSerializer): class Meta: model = FtestWork - fields = ['id', 'wm', 'mb', 'type', 'type2', 'test_date', 'count', 'count_sampling', 'count_ok', 'count_notok', 'count_notok_json', 'test_user', 'need_update_wm'] + fields = ['id', 'wm', 'mb', 'type', 'type2', 'test_date', 'count', 'count_sampling', 'count_sampling_ok', 'count_ok', 'count_notok', 'count_notok_json', 'test_user', 'need_update_wm'] extra_kwargs = {'test_user': {'required': True}, 'type': {'required': True}} def validate(self, attrs): @@ -104,6 +104,7 @@ class FtestWorkSerializer(CustomModelSerializer): source='material', read_only=True) material_cate = serializers.CharField(source='material.cate', read_only=True) mb_ = MaterialBatchDetailSerializer(source='mb', read_only=True) + test_user_name = serializers.CharField(source='test_user.name', read_only=True) class Meta: model = FtestWork From e77f3159f5419af0bfa35945be38645ef4225a12 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 10:34:45 +0800 Subject: [PATCH 035/106] =?UTF-8?q?feat:=20mtaskb=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=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/pm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index 4b06348a..93b03a54 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -211,5 +211,5 @@ class MtaskbViewSet(CustomModelViewSet): queryset = Mtaskb.objects.all() serializer_class = MtaskbSerializer update_serializer_class = MtaskbUpdateSerializer - filterset_fields = {"mtask": ["exact"], "handle_user": ["exact"]} + filterset_fields = {"mtask": ["exact"], "handle_user": ["exact"], "mgroup": ["exact"]} ordering = ['id'] \ No newline at end of file From 6e7e6c584e944b2887979ed50448f39978a61d09 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 15:25:14 +0800 Subject: [PATCH 036/106] =?UTF-8?q?feat:=20=E4=B8=80=E4=BA=8C=E7=BA=A7?= =?UTF-8?q?=E6=97=A5=E5=BF=97=E5=BD=95=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/models.py | 13 +++++--- apps/wpm/serializers.py | 68 ++++++++++++++++++++++++++++++++++++----- apps/wpm/services.py | 30 +++++++++++++----- apps/wpm/views.py | 15 ++------- 4 files changed, 93 insertions(+), 33 deletions(-) diff --git a/apps/wpm/models.py b/apps/wpm/models.py index ea45c53f..18cdf269 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -1,7 +1,7 @@ from django.db import models from apps.utils.models import CommonADModel, CommonBDModel, BaseModel from apps.mtm.models import Mgroup, Team, Shift, Material, Route -from apps.pm.models import Mtask +from apps.pm.models import Mtask, Mtaskb from apps.system.models import User from django.utils.timezone import localtime from apps.em.models import Equipment @@ -118,12 +118,14 @@ class Mlog(CommonADModel): 生产日志 """ # 变成父级的字段 - MLOG_ONETIME = 10 - MLOG_STEP = 20 + MLOG_2 = 10 + MLOG_23 = 20 + MLOG_12 = 30 MTYPE_SELF = 10 MTYPE_OUT = 20 fmlog = models.ForeignKey(Fmlog, verbose_name='关联生产日志', on_delete=models.SET_NULL, null=True, blank=True, related_name='mlog_fmlog') - fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:一次填写;20:分步填写') + mtaskb = models.ForeignKey(Mtaskb, verbose_name='关联个人任务', on_delete=models.CASCADE, related_name='mlog_mtaskb', null=True, blank=True) + fill_way = models.PositiveSmallIntegerField("填写方式", default=10, help_text='10:仅二级;20:二三级;30:一二级') mtype = models.PositiveSmallIntegerField('生产类型', default=10, help_text='10:自生产;20:外协生产', choices=((10, '自生产'), (20, '外协生产'))) supplier = models.ForeignKey(Supplier, verbose_name='外协供应商', on_delete=models.SET_NULL, null=True, blank=True) work_start_time = models.DateTimeField('生产开始时间', null=True, blank=True) @@ -223,6 +225,9 @@ class Mlog(CommonADModel): ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.SET_NULL, related_name='mlog_ticket', null=True, blank=True, db_constraint=False) test_file = models.TextField('检验文件', null=True, blank=True) + test_user = models.ForeignKey( + User, verbose_name='检验人', on_delete=models.CASCADE, null=True, blank=True, related_name='mlog_test_user') + test_time = models.DateTimeField('检验时间', null=True, blank=True) @property def mlogb(self): diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index cab75060..b36bb633 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -7,9 +7,9 @@ from datetime import datetime from .models import SfLog, StLog, SfLogExp, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog, Fmlog from apps.system.models import Dept, User from apps.system.serializers import UserSimpleSerializer -from apps.pm.models import Mtask +from apps.pm.models import Mtask, Mtaskb from apps.wpm.tasks import cal_enstat_when_pcoal_heat_change, cal_enstat_when_team_change, cal_exp_duration_sec -from apps.wpm.services import get_sflog, find_material_can_change +from apps.wpm.services import get_sflog, find_material_can_change, generate_new_batch from apps.mtm.models import Mgroup, TeamMember, Shift, Material, Route from apps.mtm.serializers import MaterialSimpleSerializer from django.db import transaction @@ -275,13 +275,20 @@ class MlogSerializer(CustomModelSerializer): } def create(self, validated_data): - mtask: Mtask = validated_data.get('mtask', None) + mtaskb: Mtaskb = validated_data.get('mtaskb', None) + if mtaskb: + mtask = mtaskb.mtask + validated_data['mtask'] = mtask + validated_data['handle_user'] = mtaskb.handle_user + else: + mtask: Mtask = validated_data.get('mtask', None) if mtask: validated_data['mgroup'] = mtask.mgroup validated_data['material_in'] = mtask.material_in material_out = mtask.material_out validated_data['material_out'] = material_out - validated_data['handle_date'] = mtask.end_date + if mtask.start_date == mtask.end_date: + validated_data['handle_date'] = mtask.end_date else: mgroup = validated_data['mgroup'] material_out = validated_data['material_out'] @@ -290,6 +297,19 @@ class MlogSerializer(CustomModelSerializer): with transaction.atomic(): mlogb = validated_data.pop('mlogb', []) instance: Mlog = super().create(validated_data) + # 自动生成mlogb + batch_in = instance.batch + if instance.wm_in: + batch_in = instance.wm_in.batch + add_dict = { + 'mlog': instance, 'batch': batch_in, 'wm_in': instance.wm_in, + 'mtask': instance.mtask, 'material_in': instance.material_in, + 'count_use': instance.count_use, 'count_break': instance.count_break, + 'count_n_jgqbl': instance.count_n_jgqbl + } + Mlogb.objects.create(**add_dict) + + # mlogb只用于组合件输出物填写 brotherId_should_list = material_out.brothers if brotherId_should_list: if mlogb: @@ -299,9 +319,29 @@ class MlogSerializer(CustomModelSerializer): mlog=instance, batch=instance.batch, mtask=instance.mtask, material_out=item['material_out'], count_ok=item['count_ok']) else: raise ValidationError('缺少产出物信息') + else: + # 生成产出物 + batch_out = validated_data.get('batch', None) + if batch_out: + pass + else: + batch_out = generate_new_batch(batch_in, instance) + + add_dict_2 = { + 'mlog': instance, 'batch': batch_out, + 'mtask': instance.mtask, 'material_out': instance.material_out, + 'count_ok': instance.count_ok, 'count_notok': instance.count_notok, + 'count_break_t': instance.count_break_t + } + for f in Mlogb._meta.fields: + if 'count_n_' in f.name and f.name != 'count_n_jgqbl': + add_dict_2[f.name] = getattr(instance, f.name) + Mlogb.objects.create(**add_dict_2) return instance def update(self, instance, validated_data): + if instance.fill_way != Mlog.MLOG_2: + raise ValidationError('不支持编辑!') validated_data.pop('mtask', None) validated_data.pop('mgroup', None) if instance.mtask: @@ -318,8 +358,16 @@ class MlogSerializer(CustomModelSerializer): return instance def validate(self, attrs): - attrs['fill_way'] = Mlog.MLOG_ONETIME + attrs['fill_way'] = Mlog.MLOG_2 attrs['mtype'] = Mlog.MTYPE_SELF # 默认为自生产 + fmlog = attrs.get('fmlog', None) + mtaskb = attrs.get('mtaskb', None) + if fmlog: + attrs['route'] = fmlog.route + attrs['mgroup'] = fmlog.mgroup + attrs['mtask'] = fmlog.mtask + if mtaskb and mtaskb.mtask != fmlog.mtask: + raise ValidationError('子任务不一致') mtask = attrs.get('mtask', None) count_notok = 0 for i in attrs: @@ -361,7 +409,7 @@ class MlogInitSerializer(CustomModelSerializer): attrs['hour_work'] = route.hour_work attrs['material_in'] = route.material_in attrs['material_out'] = route.material_out - attrs['fill_way'] = Mlog.MLOG_STEP + attrs['fill_way'] = Mlog.MLOG_23 if mtype == Mlog.MTYPE_OUT: supplier = attrs.get('supplier', None) if not supplier: @@ -371,7 +419,7 @@ class MlogInitSerializer(CustomModelSerializer): class MlogChangeSerializer(CustomModelSerializer): class Meta: model = Mlog - fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file'] + fields = ['id', 'work_end_time', 'handle_user', 'note', 'oinfo_json', 'test_file', 'test_user', 'test_time'] def validate(self, attrs): if attrs.get('work_end_time', None): @@ -620,4 +668,8 @@ class FmlogSerializer(CustomModelSerializer): class FmlogUpdateSerializer(CustomModelSerializer): class Meta: model = Fmlog - fields = ['id', 'note'] \ No newline at end of file + fields = ['id', 'note'] + + +class MlogTCreateSerializer(CustomModelSerializer): + pass \ No newline at end of file diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 5f56828a..efc6e5a6 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -18,6 +18,20 @@ from apps.wf.models import Ticket from django.db import transaction from apps.utils.thread import MyThread +def generate_new_batch(old_batch: str, mlog: Mlog): + new_batch = old_batch + supplier = mlog.supplier + process = mlog.mgroup.process + if mlog.mtype == Mlog.MTYPE_OUT: + supplier_number = supplier.number if supplier else '' + if supplier_number: + new_batch = f'{new_batch}-{supplier_number}' + elif process.batch_append_equip: + number = mlog.equipment.number if mlog.equipment else '' + if number: + new_batch = f'{new_batch}-{number}' + return new_batch + def find_material_can_change(material: Material, mgroup_to: Mgroup): """ 找到可转变为的物料(返工交接用) @@ -424,7 +438,7 @@ def cal_mlog_count_from_mlogb(mlog: Mlog): """ 通过mlogb计算mlog count 合计 """ - if mlog.fill_way == Mlog.MLOG_STEP: + if mlog.fill_way == Mlog.MLOG_23: a_dict = { "total_count_use": Sum('count_use'), "total_count_break": Sum('count_break'), @@ -455,9 +469,9 @@ def cal_mtask_progress_from_mlog(mlog: Mlog): """ 更新mlog关联的任务进度(可线程中执行) """ - if mlog.fill_way == Mlog.MLOG_ONETIME and mlog.mtask: - update_mtask(mlog.mtask, fill_way=Mlog.MLOG_ONETIME) - elif mlog.fill_way == Mlog.MLOG_STEP: + if mlog.fill_way in [Mlog.MLOG_2, Mlog.MLOG_12] and mlog.mtask: + update_mtask(mlog.mtask, fill_way=mlog.fill_way) + elif mlog.fill_way == Mlog.MLOG_23: cal_mlog_count_from_mlogb(mlog) m_outs_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) caled_mtask = [] @@ -465,7 +479,7 @@ def cal_mtask_progress_from_mlog(mlog: Mlog): mtask = item.mtask if mtask in caled_mtask: continue - update_mtask(mtask, fill_way=Mlog.MLOG_STEP) + update_mtask(mtask, fill_way=mlog.fill_way) caled_mtask.append(mtask) def cal_material_count_from_mlog(mlog: Mlog): @@ -488,7 +502,7 @@ def cal_material_count_from_mlog(mlog: Mlog): def update_mtask(mtask: Mtask, fill_way: int = 10): from apps.pm.models import Utask - if fill_way == Mlog.MLOG_ONETIME: + if fill_way == Mlog.MLOG_2: res = Mlog.objects.filter(mtask=mtask).exclude(submit_time=None).aggregate(sum_count_real=Sum( 'count_real'), sum_count_ok=Sum('count_ok'), sum_count_notok=Sum('count_notok')) mtask.count_real = res['sum_count_real'] if res['sum_count_real'] else 0 @@ -507,7 +521,7 @@ def update_mtask(mtask: Mtask, fill_way: int = 10): if Mtask.objects.filter(utask=utask).exclude(state=Mtask.MTASK_SUBMIT).count() == 0: utask.state = Utask.UTASK_SUBMIT utask.save() - elif fill_way == Mlog.MLOG_STEP: + elif fill_way in [Mlog.MLOG_23, Mlog.MLOG_12]: # 已经提交的日志 m_outs_qs_mtask = Mlogb.objects.filter(mtask=mtask, material_out__isnull=False, mlog__submit_time__isnull=False) res = m_outs_qs_mtask.aggregate( @@ -640,7 +654,7 @@ def mlog_submit_validate(ins: Mlog): raise ParseError('该日志已提交!') if ins.mtask and ins.mtask.state == Mtask.MTASK_STOP: raise ParseError('该任务已停止!') - if ins.fill_way == Mlog.MLOG_STEP: + if ins.fill_way == Mlog.MLOG_23: if not Mlogb.objects.filter(material_out__isnull=False, mlog=ins).exists(): raise ParseError('该日志未指定产出!') if not Mlogb.objects.filter(material_in__isnull=False, mlog=ins).exists(): diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 525951b2..e0ac32d5 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -26,7 +26,7 @@ from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, from .services import mlog_submit, update_mtask, handover_submit, mlog_revert, cal_material_count_from_mlog, cal_mtask_progress_from_mlog from apps.utils.thread import MyThread from apps.monitor.services import create_auditlog, delete_auditlog -from apps.wpm.services import mlog_submit_validate +from apps.wpm.services import mlog_submit_validate, generate_new_batch # Create your views here. @@ -470,8 +470,6 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust def perform_create(self, serializer): ins: Mlogb = serializer.save() mlog: Mlog = ins.mlog - process: Process = mlog.mgroup.process - supplier = mlog.supplier # 创建输出 if ins.mtask and ins.material_in: material_out = mlog.material_out @@ -482,16 +480,7 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust "mlog": ins.mlog, "material_out": ins.mlog.material_out } - new_batch = ins.batch - if mlog.mtype == Mlog.MTYPE_OUT: - supplier_number = supplier.number if supplier else '' - if supplier_number: - new_batch = f'{new_batch}-{supplier_number}' - elif process.batch_append_equip: - number = mlog.equipment.number if mlog.equipment else '' - if number: - new_batch = f'{new_batch}-{number}' - m_dict['batch'] = new_batch + m_dict['batch'] = generate_new_batch(ins.batch, mlog) Mlogb.objects.get_or_create(**m_dict, defaults=m_dict) From bae2b7b8f5f06bc5fff8142cfafa0fc9241432d7 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 15:50:07 +0800 Subject: [PATCH 037/106] =?UTF-8?q?feat:=20mlogb=20=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index b36bb633..43aeec8b 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -436,6 +436,8 @@ class MlogbInSerializer(CustomModelSerializer): def validate(self, attrs): mlog: Mlog = attrs['mlog'] mtask: Mtask = attrs['mtask'] + if mtask.submit_time is not None: + raise ValidationError('不可选择已提交的任务') wm_in: WMaterial = attrs['wm_in'] if wm_in.state != WMaterial.WM_OK: raise ValidationError('非合格品不可使用') From 463390691a41aced94e5fc5279751198450b3191 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 15:53:04 +0800 Subject: [PATCH 038/106] =?UTF-8?q?feat:=20wpm=20=E6=B7=BB=E5=8A=A0mtaskb?= =?UTF-8?q?=E7=AD=89=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0068_auto_20240904_1549.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 apps/wpm/migrations/0068_auto_20240904_1549.py diff --git a/apps/wpm/migrations/0068_auto_20240904_1549.py b/apps/wpm/migrations/0068_auto_20240904_1549.py new file mode 100644 index 00000000..968abaea --- /dev/null +++ b/apps/wpm/migrations/0068_auto_20240904_1549.py @@ -0,0 +1,37 @@ +# Generated by Django 3.2.12 on 2024-09-04 07:49 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0020_mtaskb'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('wpm', '0067_auto_20240904_0903'), + ] + + operations = [ + migrations.AddField( + model_name='mlog', + name='mtaskb', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlog_mtaskb', to='pm.mtaskb', verbose_name='关联个人任务'), + ), + migrations.AddField( + model_name='mlog', + name='test_time', + field=models.DateTimeField(blank=True, null=True, verbose_name='检验时间'), + ), + migrations.AddField( + model_name='mlog', + name='test_user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='mlog_test_user', to=settings.AUTH_USER_MODEL, verbose_name='检验人'), + ), + migrations.AlterField( + model_name='mlog', + name='fill_way', + field=models.PositiveSmallIntegerField(default=10, help_text='10:仅二级;20:二三级;30:一二级', verbose_name='填写方式'), + ), + ] From 6694820dcd9f5aa7da169337713ee3e5104b5663 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 16:00:00 +0800 Subject: [PATCH 039/106] =?UTF-8?q?fix:=20mtaskb=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E6=9D=A1=E4=BB=B6=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index 93b03a54..bc56e17c 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -211,5 +211,5 @@ class MtaskbViewSet(CustomModelViewSet): queryset = Mtaskb.objects.all() serializer_class = MtaskbSerializer update_serializer_class = MtaskbUpdateSerializer - filterset_fields = {"mtask": ["exact"], "handle_user": ["exact"], "mgroup": ["exact"]} + filterset_fields = {"mtask": ["exact"], "handle_user": ["exact"], "mtask__mgroup": ["exact"]} ordering = ['id'] \ No newline at end of file From c2649ec963d699a7cf2b85abbc588070d63935ae Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 16:13:50 +0800 Subject: [PATCH 040/106] =?UTF-8?q?feat:=20mtask=E5=A2=9E=E5=8A=A0mtaskb?= =?UTF-8?q?=E7=9A=84=E8=BF=94=E5=9B=9E=E5=B9=B6=E5=9C=A8=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=A1=AB=E5=86=99=E6=97=B6=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/models.py | 4 ++++ apps/pm/serializers.py | 28 ++++++++++++++-------------- apps/wpm/serializers.py | 2 ++ 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/apps/pm/models.py b/apps/pm/models.py index 02e6c934..82f1d699 100644 --- a/apps/pm/models.py +++ b/apps/pm/models.py @@ -112,6 +112,10 @@ class Mtask(CommonADModel): from apps.wpm.models import Mlog return Mlog.objects.filter(mtask=self) + @property + def mtaskb(self): + return Mtaskb.objects.filter(mtask=self) + class Mtaskb(BaseModel): mtask = models.ForeignKey(Mtask, verbose_name='关联任务', on_delete=models.CASCADE, related_name='b_mtask') diff --git a/apps/pm/serializers.py b/apps/pm/serializers.py index 8a6a5d8d..314463eb 100644 --- a/apps/pm/serializers.py +++ b/apps/pm/serializers.py @@ -55,6 +55,18 @@ class MlogSimpleSerializer(CustomModelSerializer): fields = ['id', 'shift_name', 'count_use', 'count_ok', 'count_real', 'submit_time'] +class MtaskbSerializer(CustomModelSerializer): + handle_user_name = serializers.StringRelatedField( + source='handle_user.name', read_only=True) + class Meta: + model = Mtaskb + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS_BASE + +class MtaskbUpdateSerializer(CustomModelSerializer): + class Meta: + model = Mtaskb + fields = ['id', 'count'] class MtaskSerializer(CustomModelSerializer): material_out_ = MaterialSimpleSerializer( @@ -67,6 +79,7 @@ class MtaskSerializer(CustomModelSerializer): source='submit_user.name', read_only=True) mgroup_name = serializers.CharField(source='mgroup.name', read_only=True) mlogs = MlogSimpleSerializer(label='日志信息', many=True, required=False) + mtaskb = MtaskbSerializer(label='子任务信息', many=True, required=False, read_only=True) class Meta: model = Mtask @@ -110,17 +123,4 @@ class MtaskDaySerializer(serializers.Serializer): class MtaskAddInfoSerializer(CustomModelSerializer): class Meta: model = Mtask - fields = ['peifen_kg'] - -class MtaskbSerializer(CustomModelSerializer): - handle_user_name = serializers.StringRelatedField( - source='handle_user.name', read_only=True) - class Meta: - model = Mtaskb - fields = '__all__' - read_only_fields = EXCLUDE_FIELDS_BASE - -class MtaskbUpdateSerializer(CustomModelSerializer): - class Meta: - model = Mtaskb - fields = ['id', 'count'] \ No newline at end of file + fields = ['peifen_kg'] \ No newline at end of file diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 43aeec8b..1904b78f 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -366,6 +366,8 @@ class MlogSerializer(CustomModelSerializer): attrs['route'] = fmlog.route attrs['mgroup'] = fmlog.mgroup attrs['mtask'] = fmlog.mtask + if attrs['mtask'].mtaskb and mtaskb is None: + raise ValidationError('子任务不能为空') if mtaskb and mtaskb.mtask != fmlog.mtask: raise ValidationError('子任务不一致') mtask = attrs.get('mtask', None) From 22052d1d829a6e5823dde7f8dc63ae2c3babcc25 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 16:21:00 +0800 Subject: [PATCH 041/106] =?UTF-8?q?fix:=20fmlog=20validate=20=E6=9C=AA?= =?UTF-8?q?=E8=BF=94=E5=9B=9Eattrs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 1904b78f..56e9f0c4 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -668,6 +668,7 @@ class FmlogSerializer(CustomModelSerializer): raise ParseError('工序不匹配') if mtask.mgroup != mgroup: raise ParseError('工段不匹配') + return attrs class FmlogUpdateSerializer(CustomModelSerializer): class Meta: From 7afa4948037abe35b9a9903e229c4dab69550895 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 16:38:21 +0800 Subject: [PATCH 042/106] =?UTF-8?q?feat:=20mtask=E5=A2=9E=E5=8A=A0mtaskb?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/serializers.py | 7 +++++++ apps/pm/views.py | 18 +++++++++++++++++- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/apps/pm/serializers.py b/apps/pm/serializers.py index 314463eb..5bea0059 100644 --- a/apps/pm/serializers.py +++ b/apps/pm/serializers.py @@ -55,6 +55,13 @@ class MlogSimpleSerializer(CustomModelSerializer): fields = ['id', 'shift_name', 'count_use', 'count_ok', 'count_real', 'submit_time'] +class MtaskbAddSerializer(CustomModelSerializer): + handle_user_name = serializers.StringRelatedField( + source='handle_user.name', read_only=True) + class Meta: + model = Mtaskb + fields = ['id', 'handle_user', 'handle_user_name', 'count'] + class MtaskbSerializer(CustomModelSerializer): handle_user_name = serializers.StringRelatedField( source='handle_user.name', read_only=True) diff --git a/apps/pm/views.py b/apps/pm/views.py index bc56e17c..f49d41a3 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -11,7 +11,8 @@ from .filters import MtaskFilter, UtaskFilter from .models import Mtask, Utask, Mtaskb from .serializers import (MtaskSerializer, SchedueSerializer, UtaskSerializer, MtaskDaySerializer, MtaskAddInfoSerializer, - SchedueMtasksSerializer, MtaskbSerializer, MtaskbUpdateSerializer) + SchedueMtasksSerializer, MtaskbSerializer, + MtaskbUpdateSerializer, MtaskbAddSerializer) from .services import PmService from django.utils import timezone @@ -206,6 +207,21 @@ class MtaskViewSet(CustomModelViewSet): sr.save() return Response() + @action(methods=['post'], detail=True, perms_map={'post': 'mlogb.create'}, serializer_class=MtaskbAddSerializer) + @transaction.atomic + def add_mtaskb(self, request, *args, **kwargs): + mtask = self.get_object() + sr = MtaskAddInfoSerializer(data=request.data, many=True) + sr.is_valid(raise_exception=True) + vdata = sr.validated_data + total = 0 + for v in vdata: + total += v['count'] + if total != mtask.count: + raise ParseError('任务数量与分配数量不匹配') + for v in vdata: + Mtaskb.objects.get_or_create(mtask=mtask, handle_user=vdata['handle_user'], count=vdata['count']) + return Response() class MtaskbViewSet(CustomModelViewSet): queryset = Mtaskb.objects.all() From 09b3f1702599d0d67117eaf5c7ae0c4d2b232c16 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 16:38:55 +0800 Subject: [PATCH 043/106] =?UTF-8?q?fix:=20add=5Fmtaskb=20perm=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/pm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index f49d41a3..dd136345 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -207,7 +207,7 @@ class MtaskViewSet(CustomModelViewSet): sr.save() return Response() - @action(methods=['post'], detail=True, perms_map={'post': 'mlogb.create'}, serializer_class=MtaskbAddSerializer) + @action(methods=['post'], detail=True, perms_map={'post': 'mtaskb.create'}, serializer_class=MtaskbAddSerializer) @transaction.atomic def add_mtaskb(self, request, *args, **kwargs): mtask = self.get_object() From e12a1042b9249b9097c9c57a08349ee1b5df4930 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 16:40:37 +0800 Subject: [PATCH 044/106] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96add=5Fmtaskb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/pm/views.py b/apps/pm/views.py index dd136345..a1c8ce7c 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -215,12 +215,15 @@ class MtaskViewSet(CustomModelViewSet): sr.is_valid(raise_exception=True) vdata = sr.validated_data total = 0 + userIds = [] for v in vdata: total += v['count'] + userIds.append(v['handle_user'].id) if total != mtask.count: raise ParseError('任务数量与分配数量不匹配') for v in vdata: Mtaskb.objects.get_or_create(mtask=mtask, handle_user=vdata['handle_user'], count=vdata['count']) + Mtaskb.objects.filter(mtask=mtask).exclude(handle_user__in=userIds).delete() return Response() class MtaskbViewSet(CustomModelViewSet): From afa55df750639700d4840413d9e52aa6d40fb88d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 16:52:23 +0800 Subject: [PATCH 045/106] =?UTF-8?q?fix:=20add=5Fmtaskb=E7=94=A8=E9=94=99?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index a1c8ce7c..d63e30b8 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -211,7 +211,7 @@ class MtaskViewSet(CustomModelViewSet): @transaction.atomic def add_mtaskb(self, request, *args, **kwargs): mtask = self.get_object() - sr = MtaskAddInfoSerializer(data=request.data, many=True) + sr = MtaskbAddSerializer(data=request.data, many=True) sr.is_valid(raise_exception=True) vdata = sr.validated_data total = 0 From ea83d57129e9e72a49b32a736a7601a3107f7f45 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 16:55:55 +0800 Subject: [PATCH 046/106] =?UTF-8?q?fix:=20add=5Fmtaskb=E7=94=A8=E9=94=99?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=E4=BA=862?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index d63e30b8..a4060f86 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -222,7 +222,7 @@ class MtaskViewSet(CustomModelViewSet): if total != mtask.count: raise ParseError('任务数量与分配数量不匹配') for v in vdata: - Mtaskb.objects.get_or_create(mtask=mtask, handle_user=vdata['handle_user'], count=vdata['count']) + Mtaskb.objects.get_or_create(mtask=mtask, handle_user=v['handle_user'], count=v['count']) Mtaskb.objects.filter(mtask=mtask).exclude(handle_user__in=userIds).delete() return Response() From 8c56523285d5a87744f57c5962af9ea38cac8873 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 17:01:08 +0800 Subject: [PATCH 047/106] =?UTF-8?q?feat:=20mlog=20=E5=A2=9E=E5=8A=A0fmlog?= =?UTF-8?q?=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/filters.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index 5499c14b..c2addaea 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -66,7 +66,8 @@ class MlogFilter(filters.FilterSet): "mtask__mgroup__belong_dept__name": ["exact", "contains", "in"], "mgroup__belong_dept__name": ["exact", "in", "contains"], "mgroup__name": ["exact", "in", "contains"], - "submit_time": ["isnull"] + "submit_time": ["isnull"], + "fmlog": ["exact"] } From 4c57c6e9eeafd388f295b1aa158107d368efcc72 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 17:19:30 +0800 Subject: [PATCH 048/106] =?UTF-8?q?feat:=20mtaskb=20=E5=88=A0=E9=99=A4?= =?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/pm/views.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index a4060f86..ecde7008 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -223,7 +223,12 @@ class MtaskViewSet(CustomModelViewSet): raise ParseError('任务数量与分配数量不匹配') for v in vdata: Mtaskb.objects.get_or_create(mtask=mtask, handle_user=v['handle_user'], count=v['count']) - Mtaskb.objects.filter(mtask=mtask).exclude(handle_user__in=userIds).delete() + dobjs = Mtaskb.objects.filter(mtask=mtask).exclude(handle_user__in=userIds) + from apps.wpm.models import Mlog + if Mlog.objects.filter(mtaskb__in=dobjs).exists(): + raise ParseError('已存在工作日志,无法修改分配') + else: + dobjs.delete() return Response() class MtaskbViewSet(CustomModelViewSet): From fc855d283062caa49584c8009de5dbc43991987b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 17:31:51 +0800 Subject: [PATCH 049/106] =?UTF-8?q?fix:=20add=5Fmtaskb=E7=94=A8=E9=94=99?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=E4=BA=863?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index ecde7008..1eb99634 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -222,7 +222,7 @@ class MtaskViewSet(CustomModelViewSet): if total != mtask.count: raise ParseError('任务数量与分配数量不匹配') for v in vdata: - Mtaskb.objects.get_or_create(mtask=mtask, handle_user=v['handle_user'], count=v['count']) + Mtaskb.objects.get_or_create(mtask=mtask, handle_user=v['handle_user'], defaults={"count": v['count']}) dobjs = Mtaskb.objects.filter(mtask=mtask).exclude(handle_user__in=userIds) from apps.wpm.models import Mlog if Mlog.objects.filter(mtaskb__in=dobjs).exists(): From 668fff3f2dd6163deab70ee809f22b730dc5f938 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 17:40:57 +0800 Subject: [PATCH 050/106] =?UTF-8?q?fix:=20add=5Fmtaskb=E7=94=A8=E9=94=99?= =?UTF-8?q?=E5=BA=8F=E5=88=97=E5=8C=96=E5=99=A8=E4=BA=864?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index 1eb99634..74f72e72 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -222,7 +222,9 @@ class MtaskViewSet(CustomModelViewSet): if total != mtask.count: raise ParseError('任务数量与分配数量不匹配') for v in vdata: - Mtaskb.objects.get_or_create(mtask=mtask, handle_user=v['handle_user'], defaults={"count": v['count']}) + mtaskb, _ = Mtaskb.objects.get_or_create(mtask=mtask, handle_user=v['handle_user']) + mtaskb.count = v['count'] + mtaskb.save() dobjs = Mtaskb.objects.filter(mtask=mtask).exclude(handle_user__in=userIds) from apps.wpm.models import Mlog if Mlog.objects.filter(mtaskb__in=dobjs).exists(): From f4f44be10121b70c8e62aa8a8842613c5e3cb423 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 17:52:37 +0800 Subject: [PATCH 051/106] =?UTF-8?q?feat:=20add=5Fmtaskb=20=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/pm/views.py b/apps/pm/views.py index 74f72e72..2ca45329 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -211,6 +211,8 @@ class MtaskViewSet(CustomModelViewSet): @transaction.atomic def add_mtaskb(self, request, *args, **kwargs): mtask = self.get_object() + if mtask.state != Mtask.MTASK_ASSGINED: + raise ParseError('该任务不可分配') sr = MtaskbAddSerializer(data=request.data, many=True) sr.is_valid(raise_exception=True) vdata = sr.validated_data From eb5a8df7e0d227c2e694049d00cc1fd76c0e3010 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 4 Sep 2024 18:21:32 +0800 Subject: [PATCH 052/106] =?UTF-8?q?feat:=20mlog=20create=20=E6=97=B6?= =?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/wpm/serializers.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 56e9f0c4..bf21fbff 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -363,13 +363,21 @@ class MlogSerializer(CustomModelSerializer): fmlog = attrs.get('fmlog', None) mtaskb = attrs.get('mtaskb', None) if fmlog: + attrs['fill_way'] = Mlog.MLOG_12 + wm_in: WMaterial = attrs.get('wm_in', None) + if wm_in: + pass + else: + raise ParseError('未提供消耗的车间物料') attrs['route'] = fmlog.route attrs['mgroup'] = fmlog.mgroup attrs['mtask'] = fmlog.mtask if attrs['mtask'].mtaskb and mtaskb is None: - raise ValidationError('子任务不能为空') + raise ParseError('子任务不能为空') if mtaskb and mtaskb.mtask != fmlog.mtask: - raise ValidationError('子任务不一致') + raise ParseError('子任务不一致') + if wm_in.material != attrs['mtask'].material_in: + raise ParseError('消耗物料与任务不一致') mtask = attrs.get('mtask', None) count_notok = 0 for i in attrs: From 982247ee70709340f5b4472bc82080b6ae0526ce Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 09:11:48 +0800 Subject: [PATCH 053/106] =?UTF-8?q?feat:=20count=5Fn=5Fjgqbl=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BAcount=5Fpn=5Fjgqbl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0064_auto_20240902_1411.py | 4 ++-- apps/wpm/models.py | 9 +++++--- apps/wpm/serializers.py | 10 ++++----- apps/wpm/services.py | 22 ++++++++++--------- 4 files changed, 25 insertions(+), 20 deletions(-) diff --git a/apps/wpm/migrations/0064_auto_20240902_1411.py b/apps/wpm/migrations/0064_auto_20240902_1411.py index f3ca18c4..8820b4a6 100644 --- a/apps/wpm/migrations/0064_auto_20240902_1411.py +++ b/apps/wpm/migrations/0064_auto_20240902_1411.py @@ -12,12 +12,12 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( model_name='mlog', - name='count_n_jgqbl', + name='count_pn_jgqbl', field=models.PositiveIntegerField(default=0, verbose_name='加工前不良'), ), migrations.AddField( model_name='mlogb', - name='count_n_jgqbl', + name='count_pn_jgqbl', field=models.PositiveIntegerField(default=0, verbose_name='加工前不良'), ), ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 18cdf269..3664c3c9 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -164,7 +164,7 @@ class Mlog(CommonADModel): count_notok = models.PositiveIntegerField('不合格数', default=0) count_break_t = models.PositiveIntegerField('检验碎料数', default=0) - count_n_jgqbl = models.PositiveIntegerField('加工前不良', default=0) + count_pn_jgqbl = models.PositiveIntegerField('加工前不良', default=0) count_n_zw = models.PositiveIntegerField('炸纹', default=0) count_n_tw = models.PositiveIntegerField('条纹', default=0) count_n_qp = models.PositiveIntegerField('气泡', default=0) @@ -263,7 +263,7 @@ class Mlogb(BaseModel): count_ok = models.PositiveIntegerField('合格数量', default=0) count_notok = models.PositiveIntegerField('不合格数', default=0) - count_n_jgqbl = models.PositiveIntegerField('加工前不良', default=0) + count_pn_jgqbl = models.PositiveIntegerField('加工前不良', default=0) # 添加不合格字段后需要更改cal_mlog_count_from_mlogb count_n_hs = models.PositiveIntegerField('划伤', default=0) count_n_qp = models.PositiveIntegerField('气泡', default=0) @@ -288,7 +288,8 @@ class Handover(CommonADModel): H_NORMAL = 10 H_REPAIR = 20 H_TEST = 30 - type = models.PositiveSmallIntegerField('交接类型', choices=[(H_NORMAL, '正常交接'), (H_REPAIR, '返修交接'), (H_TEST, '检验交接')], default=H_NORMAL) + H_SCRAP = 40 + type = models.PositiveSmallIntegerField('交接类型', choices=[(H_NORMAL, '正常交接'), (H_REPAIR, '返修交接'), (H_TEST, '检验交接'), (H_SCRAP, '报废交接')], default=H_NORMAL) send_date = models.DateField('送料日期') send_user = models.ForeignKey( User, verbose_name='交送人', on_delete=models.CASCADE, related_name='handover_send_user') @@ -318,6 +319,8 @@ class Handover(CommonADModel): submit_user = models.ForeignKey( User, verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='handover_submit_user') +class Handoverb(BaseModel): + pass class AttLog(CommonADModel): """ diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index bf21fbff..bef3798b 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -305,7 +305,7 @@ class MlogSerializer(CustomModelSerializer): 'mlog': instance, 'batch': batch_in, 'wm_in': instance.wm_in, 'mtask': instance.mtask, 'material_in': instance.material_in, 'count_use': instance.count_use, 'count_break': instance.count_break, - 'count_n_jgqbl': instance.count_n_jgqbl + 'count_pn_jgqbl': instance.count_pn_jgqbl } Mlogb.objects.create(**add_dict) @@ -334,7 +334,7 @@ class MlogSerializer(CustomModelSerializer): 'count_break_t': instance.count_break_t } for f in Mlogb._meta.fields: - if 'count_n_' in f.name and f.name != 'count_n_jgqbl': + if 'count_n_' in f.name and f.name != 'count_pn_jgqbl': add_dict_2[f.name] = getattr(instance, f.name) Mlogb.objects.create(**add_dict_2) return instance @@ -440,7 +440,7 @@ class MlogChangeSerializer(CustomModelSerializer): class MlogbInSerializer(CustomModelSerializer): class Meta: model = Mlogb - fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_n_jgqbl', 'count_break', 'note'] + fields = ['id', 'mlog', 'mtask', 'wm_in', 'count_use', 'count_pn_jgqbl', 'count_break', 'note'] extra_kwargs = {'count_use': {'required': True}, 'mtask': {'required': True}, 'wm_in': {'required': True}} def validate(self, attrs): @@ -480,13 +480,13 @@ class MlogbInSerializer(CustomModelSerializer): class MlogbInUpdateSerializer(CustomModelSerializer): class Meta: model = Mlogb - fields = ['id', 'count_use', 'count_break', 'count_n_jgqbl', 'note'] + fields = ['id', 'count_use', 'count_break', 'count_pn_jgqbl', 'note'] class MlogbOutUpdateSerializer(CustomModelSerializer): class Meta: model = Mlogb fields = "__all__" - read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break', 'count_n_jgqbl'] + read_only_fields = EXCLUDE_FIELDS_BASE + ['mlog', 'mtask', 'wm_in', 'material_in', 'material_out', 'count_use', 'count_break', 'count_pn_jgqbl'] def validate(self, attrs): count_notok_json = attrs.get('count_notok_json', []) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index efc6e5a6..96bbbaf2 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -227,8 +227,8 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): m_ins_bl_list = [] for mi in m_ins.all(): m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi.wm_in)) - if mi.count_n_jgqbl > 0: - m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_n_jgqbl)) + if mi.count_pn_jgqbl > 0: + m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_pn_jgqbl)) else: m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in)] for mi in m_ins_list: @@ -261,11 +261,11 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): wm.save() # 针对加工前不良的暂时额外处理 for item in m_ins_bl_list: - material, batch, count_n_jgqbl = item - if count_n_jgqbl> 0: + material, batch, count_pn_jgqbl = item + if count_pn_jgqbl> 0: lookup = {'batch': batch, 'material': material, 'mgroup': mgroup, 'notok_sign': 'jgqbl', 'state': WMaterial.WM_NOTOK} wm, is_create = WMaterial.objects.get_or_create(**lookup, defaults={**lookup, "belong_dept": belong_dept}) - wm.count = wm.count + item.count_n_jgqbl + wm.count = wm.count + item.count_pn_jgqbl if is_create: wm.create_by = user else: @@ -340,8 +340,8 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): m_ins_bl_list = [] for mi in m_ins.all(): m_ins_list.append((mi.material_in, mi.batch, mi.count_use, mi.wm_in)) - if mi.count_n_jgqbl > 0: - m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_n_jgqbl)) + if mi.count_pn_jgqbl > 0: + m_ins_bl_list.append((mi.material_in, mi.batch, mi.count_pn_jgqbl)) else: m_ins_list = [(material_in, mlog.batch, mlog.count_use, mlog.wm_in)] for mi in m_ins_list: @@ -365,11 +365,11 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): wm.save() # 针对加工前不良的暂时额外处理 for item in m_ins_bl_list: - material, batch, count_n_jgqbl = item - if count_n_jgqbl> 0: + material, batch, count_pn_jgqbl = item + if count_pn_jgqbl> 0: lookup = {'batch': batch, 'material': material, 'mgroup': mgroup, 'notok_sign': 'jgqbl', 'state': WMaterial.WM_NOTOK} wm, is_create = WMaterial.objects.get_or_create(**lookup, defaults={**lookup, "belong_dept": belong_dept}) - wm.count = wm.count - item.count_n_jgqbl + wm.count = wm.count - item.count_pn_jgqbl if wm.count < 0: raise ParseError('加工前不良数量大于库存量') if is_create: @@ -639,6 +639,8 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime state=WMaterial.WM_TEST, defaults={"batch": batch, "material": material, "belong_dept": handover.recive_dept, "count_xtest": 0, "state": WMaterial.WM_TEST}, ) + elif handover.type == Handover.H_SCRAP: + raise ParseError("不支持交接类型") else: raise ParseError("不支持交接类型") From 00853f395dd7e3ac63f4120e72b062a535dfb8de Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 09:29:49 +0800 Subject: [PATCH 054/106] =?UTF-8?q?feat:=20handle=5Fdate=20=E6=A0=B9?= =?UTF-8?q?=E6=8D=AEwork=5Ftime=E8=87=AA=E5=8A=A8=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, 7 insertions(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index bef3798b..c6b9e548 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -391,6 +391,13 @@ class MlogSerializer(CustomModelSerializer): if mtask: if mtask.start_date == mtask.end_date: attrs['handle_date'] = mtask.start_date + else: + if attrs['work_end_time']: + attrs['handle_date'] = attrs['work_end_time'].date() + elif attrs['work_start_time']: + attrs['handle_date'] = attrs['work_start_time'].date() + if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date: + pass else: if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date: pass From 0de377ddc4f97c9b338c408e7c52babcae23456f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 09:35:54 +0800 Subject: [PATCH 055/106] =?UTF-8?q?feat:=20=E5=8E=BB=E9=99=A4=20handle=5Fd?= =?UTF-8?q?ate=E7=9A=84=E6=97=A5=E6=9C=9F=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index c6b9e548..0b0f1504 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -396,13 +396,13 @@ class MlogSerializer(CustomModelSerializer): attrs['handle_date'] = attrs['work_end_time'].date() elif attrs['work_start_time']: attrs['handle_date'] = attrs['work_start_time'].date() - if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date: - pass - else: - if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date: - pass - else: - raise ValidationError('操作日期错误') + # if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date: + # pass + # else: + # if attrs['handle_date'] >= mtask.start_date and attrs['handle_date'] <= mtask.end_date: + # pass + # else: + # raise ValidationError('操作日期错误') return attrs From d6e3657298bb1ba8e4752cd2f935e360e52964d7 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 10:50:32 +0800 Subject: [PATCH 056/106] =?UTF-8?q?fix:=20count=5Fpn=5Fjgqbl=E7=9A=84?= =?UTF-8?q?=E6=89=A3=E5=87=8Fbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 96bbbaf2..c2995c2e 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -265,7 +265,7 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): if count_pn_jgqbl> 0: lookup = {'batch': batch, 'material': material, 'mgroup': mgroup, 'notok_sign': 'jgqbl', 'state': WMaterial.WM_NOTOK} wm, is_create = WMaterial.objects.get_or_create(**lookup, defaults={**lookup, "belong_dept": belong_dept}) - wm.count = wm.count + item.count_pn_jgqbl + wm.count = wm.count + count_pn_jgqbl if is_create: wm.create_by = user else: @@ -369,7 +369,7 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): if count_pn_jgqbl> 0: lookup = {'batch': batch, 'material': material, 'mgroup': mgroup, 'notok_sign': 'jgqbl', 'state': WMaterial.WM_NOTOK} wm, is_create = WMaterial.objects.get_or_create(**lookup, defaults={**lookup, "belong_dept": belong_dept}) - wm.count = wm.count - item.count_pn_jgqbl + wm.count = wm.count - count_pn_jgqbl if wm.count < 0: raise ParseError('加工前不良数量大于库存量') if is_create: From 2b9ec6d01c7683bfba5a0dbe7a6361e0c180b605 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 10:58:09 +0800 Subject: [PATCH 057/106] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0handoverb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0069_auto_20240905_1057.py | 40 +++++++++++++++++++ apps/wpm/models.py | 11 ++++- apps/wpm/serializers.py | 36 +++++++++++++---- 3 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 apps/wpm/migrations/0069_auto_20240905_1057.py diff --git a/apps/wpm/migrations/0069_auto_20240905_1057.py b/apps/wpm/migrations/0069_auto_20240905_1057.py new file mode 100644 index 00000000..efbae9e8 --- /dev/null +++ b/apps/wpm/migrations/0069_auto_20240905_1057.py @@ -0,0 +1,40 @@ +# Generated by Django 3.2.12 on 2024-09-05 02:57 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0068_auto_20240904_1549'), + ] + + operations = [ + migrations.AlterField( + model_name='handover', + name='batch', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='批次号'), + ), + migrations.AlterField( + model_name='handover', + name='type', + field=models.PositiveSmallIntegerField(choices=[(10, '正常交接'), (20, '返修交接'), (30, '检验交接'), (40, '报废交接')], default=10, verbose_name='交接类型'), + ), + migrations.CreateModel( + name='Handoverb', + fields=[ + ('id', models.CharField(editable=False, help_text='主键ID', max_length=20, primary_key=True, serialize=False, verbose_name='主键ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('count', models.PositiveIntegerField(default=0, verbose_name='送料数')), + ('handover', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.handover', verbose_name='关联交接记录')), + ('wm', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='handoverb_wm', to='wpm.wmaterial', verbose_name='关联车间库存')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 3664c3c9..4500fb6a 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -297,7 +297,7 @@ class Handover(CommonADModel): Mgroup, verbose_name='送料工段', on_delete=models.CASCADE, null=True, blank=True) send_dept = models.ForeignKey( Dept, verbose_name='送料部门', on_delete=models.CASCADE, related_name='handover_send_dept') - batch = models.CharField('批次号', max_length=50) + batch = models.CharField('批次号', max_length=50, null=True, blank=True) material = models.ForeignKey( Material, verbose_name='物料', on_delete=models.CASCADE, related_name='h_ma') material_changed = models.ForeignKey(Material, verbose_name='变更后物料', on_delete=models.CASCADE, null=True, blank=True, related_name='h_ma_c') @@ -319,8 +319,15 @@ class Handover(CommonADModel): submit_user = models.ForeignKey( User, verbose_name='提交人', on_delete=models.CASCADE, null=True, blank=True, related_name='handover_submit_user') + @property + def handoverb(self): + return Handoverb.objects.filter(handover=self) + class Handoverb(BaseModel): - pass + handover = models.ForeignKey(Handover, verbose_name='关联交接记录', on_delete=models.CASCADE) + wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL, + null=True, blank=True, related_name='handoverb_wm') + count = models.PositiveIntegerField('送料数', default=0) class AttLog(CommonADModel): """ diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 0b0f1504..1e464be5 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -4,7 +4,8 @@ from rest_framework import serializers from rest_framework.exceptions import ValidationError, ParseError from datetime import datetime -from .models import SfLog, StLog, SfLogExp, WMaterial, Mlog, Handover, Mlogb, AttLog, OtherLog, Fmlog +from .models import (SfLog, StLog, SfLogExp, WMaterial, Mlog, + Handover, Handoverb, Mlogb, AttLog, OtherLog, Fmlog) from apps.system.models import Dept, User from apps.system.serializers import UserSimpleSerializer from apps.pm.models import Mtask, Mtaskb @@ -542,6 +543,12 @@ class MlogRelatedSerializer(serializers.Serializer): class DeptBatchSerializer(serializers.Serializer): belong_dept_name = serializers.CharField(label='车间名称') +class HandoverbSerializer(CustomModelSerializer): + class Meta: + model = Handoverb + fields = "__all__" + read_only_fields = EXCLUDE_FIELDS_BASE + ['handover'] + extra_kwargs = {'wm': {'required': True}} class HandoverSerializer(CustomModelSerializer): # wm = serializers.PrimaryKeyRelatedField( @@ -560,12 +567,20 @@ class HandoverSerializer(CustomModelSerializer): material_name = serializers.StringRelatedField( source='material', read_only=True) wm_notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True) + handoverb = HandoverbSerializer(many=True, read_only=True) def validate(self, attrs): if 'type' not in attrs: attrs['type'] = Handover.H_NORMAL - wm:WMaterial = attrs['wm'] - material = wm.material + wm:WMaterial = attrs.get('wm', None) + handoverb = attrs.get('handoverb', []) + if wm: + material = wm.material + attrs['handoverb'] = [{"wm": wm, "count": attrs["count"] }] + elif handoverb: + wm: WMaterial = handoverb[0]["wm"] + else: + raise ParseError('必须指定车间库存') attrs['material'] = wm.material attrs['batch'] = wm.batch attrs['send_dept'] = wm.belong_dept @@ -579,10 +594,14 @@ class HandoverSerializer(CustomModelSerializer): raise ValidationError('收料车间和收料工段必须有一个') if 'send_dept' not in attrs and 'send_mgroup' not in attrs: raise ValidationError('送料车间和送料工段必须有一个') - if wm.notok_sign is not None and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]: - raise ValidationError('物料不合格,不能进行正常/检验交接') - if wm.count_xtest is not None: - raise ValidationError('物料检验中,不能进行交接') + for ind, item in enumerate(handoverb): + wm = item["wm"] + if attrs["material"] != wm.material: + raise ParseError(f'第{ind+1}物料与交接物料不一致') + if wm.notok_sign is not None 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}物料检验中,不能进行交接') return attrs class Meta: @@ -591,7 +610,7 @@ class HandoverSerializer(CustomModelSerializer): read_only_fields = EXCLUDE_FIELDS + ["mlog"] extra_kwargs = { "type": {"required": False}, - "wm": {"required": True}, + "wm": {"required": False}, "send_dept": {"required": False}, "recive_mgroup": {"required": False}, "recive_dept": {"required": False}, @@ -614,6 +633,7 @@ class HandoverUpdateSerializer(CustomModelSerializer): fields = ['id', 'send_date', 'send_user', 'count', 'count_eweight', 'recive_user'] + class GenHandoverSerializer(serializers.Serializer): mlogs = serializers.PrimaryKeyRelatedField( label='mlog的ID列表', queryset=Mlog.objects.all(), many=True) From 308fa4c7ad454d3fb25c10b0df25d65b8b38021e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 11:37:40 +0800 Subject: [PATCH 058/106] =?UTF-8?q?feat:=20=E6=8A=A5=E5=BA=9F=E4=BA=A4?= =?UTF-8?q?=E6=8E=A5=E6=97=B6=E5=9B=BA=E5=AE=9Arecive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 1e464be5..3e81f6c2 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -20,7 +20,6 @@ from django.utils.timezone import localdate from apps.qm.models import NotOkOption from apps.wf.serializers import TicketSimpleSerializer - class OtherLogSerializer(CustomModelSerializer): class Meta: model = OtherLog @@ -602,6 +601,10 @@ class HandoverSerializer(CustomModelSerializer): raise ParseError(f'第{ind+1}物料不合格,不能进行正常/检验交接') if wm.count_xtest is not None: raise ParseError(f'第{ind+1}物料检验中,不能进行交接') + if attrs['type'] == Handover.H_SCRAP: + attrs['recive_mgroup'] = attrs['send_mgroup'] + attrs['recive_dept'] = attrs['send_dept'] + attrs['recive_user'] = attrs['send_user'] return attrs class Meta: From e5ac627834d383af325415b8db39055460df5c81 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 12:29:36 +0800 Subject: [PATCH 059/106] =?UTF-8?q?feat:=20wmaterial=20filter=5Fqueryset?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E8=BF=94=E5=9B=9E=E9=9D=9E=E6=8A=A5=E5=BA=9F?= =?UTF-8?q?=E5=93=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index e0ac32d5..81566e30 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -119,6 +119,12 @@ class WMaterialViewSet(ListModelMixin, CustomGenericViewSet): 'material__number', 'material__specification', 'batch', 'material__model'] filterset_class = WMaterialFilter + def filter_queryset(self, queryset): + queryset = super().filter_queryset(queryset) + if self.request.query_params.get('state_all'): + return queryset + return queryset.exclude(state=WMaterial.WM_SCRAP) + @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=DeptBatchSerializer) @transaction.atomic def batchs(self, request): From e2f4cd161238192c4f25967df37d0462b8ef4177 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 12:44:40 +0800 Subject: [PATCH 060/106] =?UTF-8?q?feat:=20handover=5Fsubmit=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/services.py | 132 ++++++++++++++++++++----------------------- 1 file changed, 61 insertions(+), 71 deletions(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index c2995c2e..45007239 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -12,7 +12,7 @@ from apps.inm.models import MIO, MIOItem, MIOItemA from apps.pm.models import Mtask from apps.mtm.models import Mgroup, Shift, Material, Route, RoutePack -from .models import SfLog, WMaterial, Mlog, Mlogb, Handover +from .models import SfLog, WMaterial, Mlog, Mlogb, Handover, Handoverb from apps.mtm.services import cal_material_count from apps.wf.models import Ticket from django.db import transaction @@ -561,92 +561,82 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime if handover.submit_time is not None: return now = timezone.now() + handoverb_qs = Handover.objects.filter(handover=handover) need_add = True material = handover.material - batch = handover.batch - wm_from = handover.wm - if wm_from is None: - raise ParseError('找不到车间库存') if '混料' in material.name: # hard code need_add = False - count_x = wm_from.count - handover.count - if count_x < 0: - raise ParseError('车间库存不足!') - else: - wm_from.count = count_x - wm_from.save() if need_add: - if handover.type == Handover.H_NORMAL: - if handover.recive_mgroup: + if handoverb_qs.exists(): + handoverb_list = [(item.wm, item.count) for item in handoverb_qs] + else: + handoverb_list = [(handover.wm, handover.count)] + + recive_mgroup = handover.recive_mgroup + recive_dept = handover.recive_dept + for item in handoverb_list: + wm_from, xcount = item + batch = wm_from.batch + if wm_from is None: + raise ParseError('找不到车间库存') + + count_x = wm_from.count - handover.count + if count_x < 0: + raise ParseError('车间库存不足!') + else: + wm_from.count = count_x + wm_from.save() + # 开始变动 + if handover.type == Handover.H_NORMAL: wm_to, _ = WMaterial.objects.get_or_create( batch=batch, material=material, - mgroup=handover.recive_mgroup, - state=WMaterial.WM_OK, - defaults={"batch": batch, "material": material, "mgroup": handover.recive_mgroup, "belong_dept": handover.recive_dept}, + mgroup=recive_mgroup, + belong_dept=recive_dept, + state=WMaterial.WM_OK ) - else: - wm_to, _ = WMaterial.objects.get_or_create( - batch=batch, - material=material, - belong_dept=handover.recive_dept, - mgroup=None, - state=WMaterial.WM_OK, - defaults={"batch": batch, "material": material, "belong_dept": handover.recive_dept} - ) - elif handover.type == Handover.H_REPAIR: - if handover.recive_mgroup: + elif handover.type == Handover.H_REPAIR: + if handover.recive_mgroup: + wm_to, _ = WMaterial.objects.get_or_create( + batch=batch, + material=handover.material_changed, + mgroup=recive_mgroup, + belong_dept=recive_dept, + notok_sign=wm_from.notok_sign, + material_origin=material, + state=WMaterial.WM_REPAIR + ) + else: + raise ParseError("返工交接必须指定接收工段") + elif handover.type == Handover.H_TEST: wm_to, _ = WMaterial.objects.get_or_create( batch=batch, - material=handover.material_changed, - mgroup=handover.recive_mgroup, - notok_sign=handover.wm.notok_sign, - material_origin=handover.material, - state=WMaterial.WM_REPAIR, + material=material, + mgroup=recive_mgroup, + state=WMaterial.WM_TEST, + belong_dept=recive_dept, defaults={ - "batch": batch, - "material": handover.material_changed, - "mgroup": handover.recive_mgroup, - "notok_sign": handover.wm.notok_sign, - "material_origin": handover.material, - "belong_dept": handover.recive_dept, - "state": WMaterial.WM_REPAIR + "count_xtest": 0, }, ) + elif handover.type == Handover.H_SCRAP: + if recive_mgroup: + wm_to, _ = WMaterial.objects.get_or_create( + batch=batch, + material=material, + mgroup=recive_mgroup, + belong_dept=recive_dept, + notok_sign=wm_from.notok_sign, + state=WMaterial.WM_SCRAP + ) + else: + raise ParseError("不支持非工段报废") else: - raise ParseError("返工交接必须指定接收工段") - elif handover.type == Handover.H_TEST: - if handover.recive_mgroup: - wm_to, _ = WMaterial.objects.get_or_create( - batch=batch, - material=material, - mgroup=handover.recive_mgroup, - state=WMaterial.WM_TEST, - defaults={ - "batch": batch, - "material": material, - "mgroup": handover.recive_mgroup, - "belong_dept": handover.recive_dept, - "count_xtest": 0, - "state": WMaterial.WM_TEST}, - ) - else: - wm_to, _ = WMaterial.objects.get_or_create( - batch=batch, - material=material, - belong_dept=handover.recive_dept, - mgroup=None, - state=WMaterial.WM_TEST, - defaults={"batch": batch, "material": material, "belong_dept": handover.recive_dept, "count_xtest": 0, "state": WMaterial.WM_TEST}, - ) - elif handover.type == Handover.H_SCRAP: - raise ParseError("不支持交接类型") - else: - raise ParseError("不支持交接类型") + raise ParseError("不支持该交接类型") - wm_to.count = wm_to.count + handover.count - wm_to.count_eweight = handover.count_eweight # 这行代码有隐患 - wm_to.save() + wm_to.count = wm_to.count + xcount + wm_to.count_eweight = handover.count_eweight # 这行代码有隐患 + wm_to.save() handover.submit_user = user handover.submit_time = now handover.save() From 0baec25a8b39ce75a401a5af8a2301289a50002d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 12:50:51 +0800 Subject: [PATCH 061/106] =?UTF-8?q?feat:=20handover=20count=E5=8F=AF?= =?UTF-8?q?=E4=B8=8D=E5=A1=AB=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 3e81f6c2..0f4fa288 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -593,14 +593,17 @@ class HandoverSerializer(CustomModelSerializer): raise ValidationError('收料车间和收料工段必须有一个') if 'send_dept' not in attrs and 'send_mgroup' not in attrs: raise ValidationError('送料车间和送料工段必须有一个') + t_count = 0 for ind, item in enumerate(handoverb): wm = item["wm"] + t_count += item["count"] if attrs["material"] != wm.material: raise ParseError(f'第{ind+1}物料与交接物料不一致') if wm.notok_sign is not None 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}物料检验中,不能进行交接') + attrs["count"] = t_count if attrs['type'] == Handover.H_SCRAP: attrs['recive_mgroup'] = attrs['send_mgroup'] attrs['recive_dept'] = attrs['send_dept'] @@ -619,6 +622,8 @@ class HandoverSerializer(CustomModelSerializer): "recive_dept": {"required": False}, "material": {"required": False}, "batch": {"required": False}, + "count": {"required": False}, + "count_eweight": {"required": False} } def create(self, validated_data): From c2e2465439dd2694df9c2db1e2e64200b6865115 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 13:09:11 +0800 Subject: [PATCH 062/106] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96mtask=20list?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/pm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/pm/views.py b/apps/pm/views.py index 2ca45329..391d7f90 100644 --- a/apps/pm/views.py +++ b/apps/pm/views.py @@ -131,7 +131,7 @@ class MtaskViewSet(CustomModelViewSet): serializer_class = MtaskSerializer filterset_class = MtaskFilter select_related_fields = ['material_in', 'material_out', 'mgroup'] - prefetch_related_fields = ['mlog_mtask'] + prefetch_related_fields = ['mlog_mtask', 'b_mtask'] ordering_fields = ['start_date', 'mgroup__process__sort', 'create_time'] ordering = ['-start_date', 'mgroup__process__sort', '-create_time'] From a1871a3763807aef4236eb1e415b4fe5a26b0bcb Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 13:14:12 +0800 Subject: [PATCH 063/106] =?UTF-8?q?feat:=20mloginit=20=E5=8F=AF=E5=A1=ABen?= =?UTF-8?q?d=5Ftime=E5=8F=8Atest=5Fuser=5Fname=20=E8=BF=94=E5=9B=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 5 ++++- apps/wpm/views.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 0f4fa288..1821b34a 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -264,6 +264,7 @@ class MlogSerializer(CustomModelSerializer): equipments_name = serializers.StringRelatedField( source='equipments', read_only=True, many=True) ticket_ = TicketSimpleSerializer(source='ticket', read_only=True) + test_user_name = serializers.CharField(source='test_user.name', read_only=True) class Meta: model = Mlog @@ -409,7 +410,7 @@ class MlogSerializer(CustomModelSerializer): class MlogInitSerializer(CustomModelSerializer): class Meta: model = Mlog - fields = ['id', 'work_start_time', 'mgroup', 'reminder_interval_list', 'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier'] + fields = ['id', 'work_start_time', 'work_end_time', 'mgroup', 'reminder_interval_list', 'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier'] extra_kwargs = { 'work_start_time': {'required': True}, 'route':{'required': True}, @@ -431,6 +432,8 @@ class MlogInitSerializer(CustomModelSerializer): supplier = attrs.get('supplier', None) if not supplier: raise ValidationError('外协必须选择外协单位') + if attrs.get('work_end_time', None): + attrs['handle_date'] = localdate(attrs['work_end_time']) return attrs class MlogChangeSerializer(CustomModelSerializer): diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 81566e30..071a4794 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -151,7 +151,7 @@ class MlogViewSet(CustomModelViewSet): select_related_fields = ['create_by', 'update_by', 'mtask', 'handle_user', 'handle_user_2', 'equipment', 'equipment_2', 'material_in', 'material_out', - 'supplier', 'ticket', 'mgroup__process'] + 'supplier', 'ticket', 'mgroup__process', 'test_user'] prefetch_related_fields = ['handle_users', 'material_outs', 'b_mlog', 'equipments'] filterset_class = MlogFilter From 97dae726172641cef3719f721bd2e09b121a0296 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 13:57:46 +0800 Subject: [PATCH 064/106] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0mloginit?= =?UTF-8?q?=E7=9A=84=E5=8F=AF=E7=94=A8=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 1821b34a..1576bdc6 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -410,7 +410,9 @@ class MlogSerializer(CustomModelSerializer): class MlogInitSerializer(CustomModelSerializer): class Meta: model = Mlog - fields = ['id', 'work_start_time', 'work_end_time', 'mgroup', 'reminder_interval_list', 'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier'] + fields = ['id', + 'work_start_time', 'work_end_time', 'mgroup', 'reminder_interval_list', + 'route', 'equipment', 'handle_user', 'note', 'mtype', 'supplier', 'test_file', 'test_user', 'test_time', 'oinfo_json'] extra_kwargs = { 'work_start_time': {'required': True}, 'route':{'required': True}, From 1243a504637c9c7d2c90e74b4ccc51a9039d7ef0 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 14:17:21 +0800 Subject: [PATCH 065/106] =?UTF-8?q?feat:=20mlog=E8=BF=94=E5=9B=9Eroutepack?= =?UTF-8?q?=5Fname?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 071a4794..909a8959 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -150,7 +150,7 @@ class MlogViewSet(CustomModelViewSet): serializer_class = MlogSerializer select_related_fields = ['create_by', 'update_by', 'mtask', 'handle_user', 'handle_user_2', 'equipment', - 'equipment_2', 'material_in', 'material_out', + 'equipment_2', 'material_in', 'material_out', 'route__routepack' 'supplier', 'ticket', 'mgroup__process', 'test_user'] prefetch_related_fields = ['handle_users', 'material_outs', 'b_mlog', 'equipments'] From 51a649c86489323cfa96b83b0d3b40f05a32b5db Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 14:17:54 +0800 Subject: [PATCH 066/106] =?UTF-8?q?feat:=20mlog=E8=BF=94=E5=9B=9Eroutepack?= =?UTF-8?q?=5Fname2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 1576bdc6..5b925b6d 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -215,6 +215,7 @@ class MlogbDetailSerializer(CustomModelSerializer): class MlogSerializer(CustomModelSerializer): mstate_json = serializers.JSONField(source='mgroup.process.mstate_json', read_only=True) supplier_name = serializers.CharField(source='supplier.name', read_only=True) + routepack_name = serializers.CharField(source='route.routepack.name', read_only=True) belong_dept = serializers.CharField( source='mgroup.belong_dept.id', read_only=True) belong_dept_name = serializers.CharField( @@ -458,8 +459,8 @@ class MlogbInSerializer(CustomModelSerializer): def validate(self, attrs): mlog: Mlog = attrs['mlog'] mtask: Mtask = attrs['mtask'] - if mtask.submit_time is not None: - raise ValidationError('不可选择已提交的任务') + if mtask.state != Mtask.MTASK_ASSGINED: + raise ValidationError('该任务非下达中不可选择') wm_in: WMaterial = attrs['wm_in'] if wm_in.state != WMaterial.WM_OK: raise ValidationError('非合格品不可使用') @@ -711,6 +712,8 @@ class FmlogSerializer(CustomModelSerializer): def validate(self, attrs): route: Route = attrs['route'] mtask: Mtask = attrs['mtask'] + if mtask.state != Mtask.MTASK_ASSGINED: + raise ParseError('该任务非下达中不可选择') mgroup: Mgroup = attrs['mgroup'] if route.process != mgroup.process: raise ParseError('工序不匹配') From ec441d770b3ca22f249840e2c4e0bed44dc9ad99 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 14:56:55 +0800 Subject: [PATCH 067/106] =?UTF-8?q?feat:=20handover=20create=20=E5=AF=B9ha?= =?UTF-8?q?ndoverb=E8=BF=9B=E8=A1=8C=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 5b925b6d..a6d48872 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -634,12 +634,17 @@ class HandoverSerializer(CustomModelSerializer): def create(self, validated_data): type = validated_data['type'] + handoverb = validated_data.pop('handoverb', []) if type == Handover.H_REPAIR: recive_mgroup = validated_data.get("recive_mgroup", None) if recive_mgroup is None: raise ParseError('返工交接需指定工段') validated_data['material_changed'] = find_material_can_change(validated_data['material'], recive_mgroup) - return super().create(validated_data) + with transaction.atomic(): + ins = super().create(validated_data) + for item in handoverb: + Handoverb.objects.get_or_create(handover=ins, wm=item["wm"], count=item["count"]) + return ins class HandoverUpdateSerializer(CustomModelSerializer): class Meta: From beb6b797095715acbafb4a3e263dc783fde10696 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 15:00:40 +0800 Subject: [PATCH 068/106] fix: mlog view select related --- apps/wpm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 909a8959..2a920520 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -150,7 +150,7 @@ class MlogViewSet(CustomModelViewSet): serializer_class = MlogSerializer select_related_fields = ['create_by', 'update_by', 'mtask', 'handle_user', 'handle_user_2', 'equipment', - 'equipment_2', 'material_in', 'material_out', 'route__routepack' + 'equipment_2', 'material_in', 'material_out', 'route__routepack', 'supplier', 'ticket', 'mgroup__process', 'test_user'] prefetch_related_fields = ['handle_users', 'material_outs', 'b_mlog', 'equipments'] From 4b44b40c77f2279cd90de8573f1d24d137866556 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 15:13:50 +0800 Subject: [PATCH 069/106] =?UTF-8?q?fix:=20handoverb=20validate=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 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index a6d48872..95aed8f9 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -582,6 +582,7 @@ class HandoverSerializer(CustomModelSerializer): if wm: material = wm.material attrs['handoverb'] = [{"wm": wm, "count": attrs["count"] }] + handoverb = attrs['handoverb'] elif handoverb: wm: WMaterial = handoverb[0]["wm"] else: @@ -600,7 +601,7 @@ class HandoverSerializer(CustomModelSerializer): if 'send_dept' not in attrs and 'send_mgroup' not in attrs: raise ValidationError('送料车间和送料工段必须有一个') t_count = 0 - for ind, item in enumerate(handoverb): + for ind, item in enumerate(attrs['handoverb']): wm = item["wm"] t_count += item["count"] if attrs["material"] != wm.material: From e51960d5ba2e617c2b863914038d325408cecc8f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 15:17:58 +0800 Subject: [PATCH 070/106] fix: handover_submit bug --- apps/wpm/services.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 45007239..60a70e6b 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -561,7 +561,7 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime if handover.submit_time is not None: return now = timezone.now() - handoverb_qs = Handover.objects.filter(handover=handover) + handoverb_qs = Handoverb.objects.filter(handover=handover) need_add = True material = handover.material if '混料' in material.name: # hard code From 2ce99bc8425f43ed5ecf2299ebce149b01e47dc9 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 15:41:24 +0800 Subject: [PATCH 071/106] fix: handoverbserializer handoverb --- 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 95aed8f9..509d47a9 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -572,7 +572,7 @@ class HandoverSerializer(CustomModelSerializer): material_name = serializers.StringRelatedField( source='material', read_only=True) wm_notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True) - handoverb = HandoverbSerializer(many=True, read_only=True) + handoverb = HandoverbSerializer(many=True) def validate(self, attrs): if 'type' not in attrs: From 38ba04cc8058a481798100dff945809743feb685 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 15:52:22 +0800 Subject: [PATCH 072/106] =?UTF-8?q?fix:=20handoverserializer=20mgroup=20?= =?UTF-8?q?=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 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 509d47a9..59914f5e 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -590,8 +590,8 @@ class HandoverSerializer(CustomModelSerializer): attrs['material'] = wm.material attrs['batch'] = wm.batch attrs['send_dept'] = wm.belong_dept - if attrs['wm'].mgroup: - attrs['send_mgroup'] = wm.mgroup + if handoverb[0]["wm"].mgroup: + attrs['send_mgroup'] = handoverb[0]["wm"].mgroup if material.process and material.process.into_wm_mgroup and 'recive_mgroup' not in attrs: raise ValidationError('必须指定交接工段') if 'recive_mgroup' in attrs and attrs['recive_mgroup']: From ee7b7a526c17399494c203bddc8269264087c9f4 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 16:38:39 +0800 Subject: [PATCH 073/106] =?UTF-8?q?fix:=20handoverb=20=E6=A0=A1=E9=AA=8C?= 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 59914f5e..17144e96 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -592,7 +592,7 @@ class HandoverSerializer(CustomModelSerializer): attrs['send_dept'] = wm.belong_dept if handoverb[0]["wm"].mgroup: attrs['send_mgroup'] = handoverb[0]["wm"].mgroup - if material.process and material.process.into_wm_mgroup and 'recive_mgroup' not in attrs: + if attrs['material'].process and attrs['material'].process.into_wm_mgroup and 'recive_mgroup' not in attrs: raise ValidationError('必须指定交接工段') if 'recive_mgroup' in attrs and attrs['recive_mgroup']: attrs['recive_dept'] = attrs['recive_mgroup'].belong_dept From 789ffe53d34c880d73cf89af6c92c2f1a9df0c63 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 17:02:06 +0800 Subject: [PATCH 074/106] =?UTF-8?q?fix:=20handoverb=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 17144e96..6cd931a4 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -580,7 +580,6 @@ class HandoverSerializer(CustomModelSerializer): wm:WMaterial = attrs.get('wm', None) handoverb = attrs.get('handoverb', []) if wm: - material = wm.material attrs['handoverb'] = [{"wm": wm, "count": attrs["count"] }] handoverb = attrs['handoverb'] elif handoverb: @@ -615,6 +614,11 @@ class HandoverSerializer(CustomModelSerializer): attrs['recive_mgroup'] = attrs['send_mgroup'] attrs['recive_dept'] = attrs['send_dept'] attrs['recive_user'] = attrs['send_user'] + if attrs['type'] == Handover.H_REPAIR: + recive_mgroup = attrs.get("recive_mgroup", None) + if recive_mgroup is None: + raise ParseError('返工交接需指定工段') + attrs['material_changed'] = find_material_can_change(attrs['material'], recive_mgroup) return attrs class Meta: @@ -634,18 +638,25 @@ class HandoverSerializer(CustomModelSerializer): } def create(self, validated_data): - type = validated_data['type'] handoverb = validated_data.pop('handoverb', []) - if type == Handover.H_REPAIR: - recive_mgroup = validated_data.get("recive_mgroup", None) - if recive_mgroup is None: - raise ParseError('返工交接需指定工段') - validated_data['material_changed'] = find_material_can_change(validated_data['material'], recive_mgroup) with transaction.atomic(): ins = super().create(validated_data) for item in handoverb: Handoverb.objects.get_or_create(handover=ins, wm=item["wm"], count=item["count"]) return ins + + def update(self, instance, validated_data): + handoverb = validated_data.pop('handoverb', []) + with transaction.atomic(): + super().update(instance, validated_data) + wmIds = [] + for item in handoverb: + wmIds.append(item["wm"].id) + hb, _ = Handoverb.objects.get_or_create(handover=instance, wm=item["wm"]) + hb.count = item["count"] + hb.save() + Handoverb.objects.filter(handover=instance).exclude(wm__in=wmIds).delete() + return instance class HandoverUpdateSerializer(CustomModelSerializer): class Meta: From ba8bc4fb721ea5bf8016df3346c2a6141d5eb15f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 17:50:04 +0800 Subject: [PATCH 075/106] fix: handover_submit --- apps/wpm/serializers.py | 2 +- apps/wpm/services.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 6cd931a4..ec551dd8 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -582,12 +582,12 @@ class HandoverSerializer(CustomModelSerializer): if wm: attrs['handoverb'] = [{"wm": wm, "count": attrs["count"] }] handoverb = attrs['handoverb'] + attrs['batch'] = wm.batch elif handoverb: wm: WMaterial = handoverb[0]["wm"] else: raise ParseError('必须指定车间库存') attrs['material'] = wm.material - attrs['batch'] = wm.batch attrs['send_dept'] = wm.belong_dept if handoverb[0]["wm"].mgroup: attrs['send_mgroup'] = handoverb[0]["wm"].mgroup diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 60a70e6b..61ccac0e 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -580,7 +580,7 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime if wm_from is None: raise ParseError('找不到车间库存') - count_x = wm_from.count - handover.count + count_x = wm_from.count - xcount if count_x < 0: raise ParseError('车间库存不足!') else: From fbaf4b576740a39cf5625844996f48f15482fbc0 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 5 Sep 2024 19:08:51 +0800 Subject: [PATCH 076/106] =?UTF-8?q?feat:=20mlog=2012=20=E6=94=AF=E6=8C=81u?= =?UTF-8?q?pdate?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 84 +++++++++++++++++++++++++++++------------ 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index ec551dd8..9989011a 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -277,25 +277,7 @@ class MlogSerializer(CustomModelSerializer): } def create(self, validated_data): - mtaskb: Mtaskb = validated_data.get('mtaskb', None) - if mtaskb: - mtask = mtaskb.mtask - validated_data['mtask'] = mtask - validated_data['handle_user'] = mtaskb.handle_user - else: - mtask: Mtask = validated_data.get('mtask', None) - if mtask: - validated_data['mgroup'] = mtask.mgroup - validated_data['material_in'] = mtask.material_in - material_out = mtask.material_out - validated_data['material_out'] = material_out - if mtask.start_date == mtask.end_date: - validated_data['handle_date'] = mtask.end_date - else: - mgroup = validated_data['mgroup'] - material_out = validated_data['material_out'] - if not (mgroup and material_out): - raise ValidationError('缺少工段或产物!') + material_out = validated_data['material_out'] with transaction.atomic(): mlogb = validated_data.pop('mlogb', []) instance: Mlog = super().create(validated_data) @@ -336,14 +318,14 @@ class MlogSerializer(CustomModelSerializer): 'count_break_t': instance.count_break_t } for f in Mlogb._meta.fields: - if 'count_n_' in f.name and f.name != 'count_pn_jgqbl': + if 'count_n_' in f.name: add_dict_2[f.name] = getattr(instance, f.name) Mlogb.objects.create(**add_dict_2) return instance def update(self, instance, validated_data): - if instance.fill_way != Mlog.MLOG_2: - raise ValidationError('不支持编辑!') + if instance.fill_way == Mlog.MLOG_23: + raise ParseError('不支持的填写类型') validated_data.pop('mtask', None) validated_data.pop('mgroup', None) if instance.mtask: @@ -351,12 +333,47 @@ class MlogSerializer(CustomModelSerializer): # validated_data.pop('handle_user', None) with transaction.atomic(): mlogb = validated_data.pop('mlogb', []) - instance = super().update(instance, validated_data) - if mlogb: + instance: Mlog = super().update(instance, validated_data) + if instance.fill_way == Mlog.MLOG_12: + # 自动生成mlogb + batch_in = instance.batch + if instance.wm_in: + batch_in = instance.wm_in.batch + minx, _ = Mlogb.objects.get_or_create( + mlog=instance, + batch=batch_in, + wm_in=instance.wm_in, + mtask=instance.mtask, + material_in=instance.material_in + ) + minx.count_use = instance.count_use + minx.count_break = instance.count_break + minx.count_pn_jgqbl = instance.count_pn_jgqbl + minx.save() + + if mlogb and instance.fill_way == Mlog.MLOG_2: Mlogb.objects.filter(mlog=instance, material_out__isnull=False).update(count_ok=0) for item in mlogb: Mlogb.objects.filter(mlog=instance, material_out=item['material_out']).update( count_ok=item['count_ok']) + elif instance.fill_way == Mlog.MLOG_12: + # 生成产出物 + batch_out = instance.batch + if batch_out: + pass + else: + batch_out = generate_new_batch(batch_in, instance) + + mox, _ = Mlogb.objects.get_or_create(mlog=instance, batch=batch_out, + mtask=instance.mtask, material_out=instance.material_out) + mox.count_ok = instance.count_ok + mox.count_notok = instance.count_notok + mox.count_break_t = instance.count_break_t + mox.save() + for f in Mlogb._meta.fields: + if 'count_n_' in f.name: + setattr(mox, f.name, getattr(instance, f.name)) + Mlogb.objects.filter(mlog=instance, material_out__isnull=False).exclude(id=mox.id).delete() return instance def validate(self, attrs): @@ -405,6 +422,25 @@ class MlogSerializer(CustomModelSerializer): # pass # else: # raise ValidationError('操作日期错误') + mtaskb: Mtaskb = attrs.get('mtaskb', None) + if mtaskb: + mtask = mtaskb.mtask + attrs['mtask'] = mtask + attrs['handle_user'] = mtaskb.handle_user + else: + mtask: Mtask = attrs.get('mtask', None) + if mtask: + attrs['mgroup'] = mtask.mgroup + attrs['material_in'] = mtask.material_in + material_out = mtask.material_out + attrs['material_out'] = material_out + if mtask.start_date == mtask.end_date: + attrs['handle_date'] = mtask.end_date + else: + mgroup = attrs['mgroup'] + material_out = attrs['material_out'] + if not (mgroup and material_out): + raise ValidationError('缺少工段或产物!') return attrs From ee89b0bdedba8954e79b2b1340816453bb51e94a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 6 Sep 2024 09:31:00 +0800 Subject: [PATCH 077/106] =?UTF-8?q?feat:=20handover=20=E6=8A=A5=E5=BA=9F?= =?UTF-8?q?=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 | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 9989011a..1814e00c 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -646,10 +646,6 @@ class HandoverSerializer(CustomModelSerializer): if wm.count_xtest is not None: raise ParseError(f'第{ind+1}物料检验中,不能进行交接') attrs["count"] = t_count - if attrs['type'] == Handover.H_SCRAP: - attrs['recive_mgroup'] = attrs['send_mgroup'] - attrs['recive_dept'] = attrs['send_dept'] - attrs['recive_user'] = attrs['send_user'] if attrs['type'] == Handover.H_REPAIR: recive_mgroup = attrs.get("recive_mgroup", None) if recive_mgroup is None: From b6b72b28266f94bea9d823ffe9a4d3f9818d5747 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 6 Sep 2024 10:01:47 +0800 Subject: [PATCH 078/106] fix: handover submit need_add --- apps/wpm/services.py | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 61ccac0e..a85f9c46 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -566,26 +566,26 @@ def handover_submit(handover: Handover, user: User, now: Union[datetime.datetime material = handover.material if '混料' in material.name: # hard code need_add = False - if need_add: - if handoverb_qs.exists(): - handoverb_list = [(item.wm, item.count) for item in handoverb_qs] + if handoverb_qs.exists(): + handoverb_list = [(item.wm, item.count) for item in handoverb_qs] + else: + handoverb_list = [(handover.wm, handover.count)] + + recive_mgroup = handover.recive_mgroup + recive_dept = handover.recive_dept + for item in handoverb_list: + wm_from, xcount = item + batch = wm_from.batch + if wm_from is None: + raise ParseError('找不到车间库存') + + count_x = wm_from.count - xcount + if count_x < 0: + raise ParseError('车间库存不足!') else: - handoverb_list = [(handover.wm, handover.count)] - - recive_mgroup = handover.recive_mgroup - recive_dept = handover.recive_dept - for item in handoverb_list: - wm_from, xcount = item - batch = wm_from.batch - if wm_from is None: - raise ParseError('找不到车间库存') - - count_x = wm_from.count - xcount - if count_x < 0: - raise ParseError('车间库存不足!') - else: - wm_from.count = count_x - wm_from.save() + wm_from.count = count_x + wm_from.save() + if need_add: # 开始变动 if handover.type == Handover.H_NORMAL: wm_to, _ = WMaterial.objects.get_or_create( From 7510b2fc318aba43330340dd9989b61169983f1a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 6 Sep 2024 10:11:44 +0800 Subject: [PATCH 079/106] =?UTF-8?q?feat:=20=E6=8A=A5=E5=BA=9F=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E4=B8=8D=E9=9C=80=E8=A6=81=E9=99=90=E5=88=B6=E6=8E=A5?= =?UTF-8?q?=E6=94=B6=E4=BA=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/views.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 2a920520..005d86a2 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -347,10 +347,11 @@ class HandoverViewSet(CustomModelViewSet): """ ins: Handover = self.get_object() user: User = self.request.user - if user == ins.recive_user or user.belong_dept == ins.recive_user.belong_dept: - pass - else: - raise ParseError('非接收人不可提交') + if ins.type != Handover.H_SCRAP: + if user == ins.recive_user or user.belong_dept == ins.recive_user.belong_dept: + pass + else: + raise ParseError('非接收人不可提交') if ins.submit_time is None: handover_submit(ins, user, None) return Response() From aab98fba62662a2086652515672211a8ff9fb19d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 6 Sep 2024 11:16:23 +0800 Subject: [PATCH 080/106] =?UTF-8?q?fix:=20mlog=20update=20=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 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 1814e00c..c7a0760f 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -369,10 +369,10 @@ class MlogSerializer(CustomModelSerializer): mox.count_ok = instance.count_ok mox.count_notok = instance.count_notok mox.count_break_t = instance.count_break_t - mox.save() for f in Mlogb._meta.fields: if 'count_n_' in f.name: setattr(mox, f.name, getattr(instance, f.name)) + mox.save() Mlogb.objects.filter(mlog=instance, material_out__isnull=False).exclude(id=mox.id).delete() return instance From 4e5d16f7f66c81f72bb66a22cb8bb239c686d5e0 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 6 Sep 2024 11:26:31 +0800 Subject: [PATCH 081/106] =?UTF-8?q?feat:=20handoverb=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=9B=B4=E5=A4=9A=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index c7a0760f..763cbcee 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -585,6 +585,8 @@ class DeptBatchSerializer(serializers.Serializer): belong_dept_name = serializers.CharField(label='车间名称') class HandoverbSerializer(CustomModelSerializer): + batch = serializers.CharFIeld(source='wm.batch', read_only=True) + notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True) class Meta: model = Handoverb fields = "__all__" From c07d0666c09eb3185800b0b9590730c825df050b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 6 Sep 2024 11:30:43 +0800 Subject: [PATCH 082/106] =?UTF-8?q?fix:=20handoverb=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E6=9B=B4=E5=A4=9A=E4=BF=A1=E6=81=AF?= 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 763cbcee..5611e42c 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -585,7 +585,7 @@ class DeptBatchSerializer(serializers.Serializer): belong_dept_name = serializers.CharField(label='车间名称') class HandoverbSerializer(CustomModelSerializer): - batch = serializers.CharFIeld(source='wm.batch', read_only=True) + batch = serializers.CharField(source='wm.batch', read_only=True) notok_sign = serializers.CharField(source='wm.notok_sign', read_only=True) class Meta: model = Handoverb From bb270d7105b50f5066a56c24a5fc715d55847e6f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sun, 8 Sep 2024 14:32:49 +0800 Subject: [PATCH 083/106] =?UTF-8?q?feat:=20inm=20mio=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0inout=5Fdate=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/inm/serializers.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/inm/serializers.py b/apps/inm/serializers.py index 4e0ba42a..866c337b 100644 --- a/apps/inm/serializers.py +++ b/apps/inm/serializers.py @@ -168,6 +168,7 @@ class MIODoSerializer(CustomModelSerializer): model = MIO fields = ['id', 'number', 'note', 'do_user', 'belong_dept', 'type', 'inout_date', 'mgroup'] + extra_kwargs = {'inout_date': {'required': True}, 'do_user': {'required': True}} def validate(self, attrs): if 'mgroup' in attrs and attrs['mgroup']: @@ -193,6 +194,7 @@ class MIOSaleSerializer(CustomModelSerializer): class Meta: model = MIO fields = ['id', 'number', 'note', 'order', 'inout_date', 'customer'] + extra_kwargs = {'inout_date': {'required': True}} def create(self, validated_data): validated_data['type'] = MIO.MIO_TYPE_SALE_OUT @@ -219,6 +221,7 @@ class MIOPurSerializer(CustomModelSerializer): class Meta: model = MIO fields = ['id', 'number', 'note', 'pu_order', 'inout_date', 'supplier'] + extra_kwargs = {'inout_date': {'required': True}} def create(self, validated_data): validated_data['type'] = MIO.MIO_TYPE_PUR_IN @@ -244,6 +247,7 @@ class MIOOtherSerializer(CustomModelSerializer): model = MIO fields = ['id', 'number', 'note', 'supplier', 'customer', 'type', 'inout_date'] + extra_kwargs = {'inout_date': {'required': True}} def create(self, validated_data): if validated_data['type'] not in [MIO.MIO_TYPE_OTHER_OUT, MIO.MIO_TYPE_OTHER_IN]: From 01cff014ffa7555738079fee3b5c5c229524c6fb Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sun, 8 Sep 2024 14:33:09 +0800 Subject: [PATCH 084/106] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0wpm=20datax?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 apps/wpm/datax.py diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py new file mode 100644 index 00000000..11c0628e --- /dev/null +++ b/apps/wpm/datax.py @@ -0,0 +1,19 @@ +from apps.utils.viewsets import GenericViewSet +from rest_framework.decorators import action +from apps.em.models import Equipment +from apps.wpm.modes import Mlog +from django.utils import timezone + +class AnaViewSet(GenericViewSet): + perms_map = {} + @action(methods=['post'], detail=False, perms_map={'post': '*'}) + def 设备最后生产日志(self, request): + data = request.data + now = timezone.now() + mgroup_name = data["mgroup_name"] + # 生产设备 + equip_qs = Equipment.objects.filter(mgroup__name=mgroup_name, type = 10) + # 设备最后生产日志 + mlog_qs = Mlog.objects.filter(equip__in=equip_qs) + mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__isnull=True) + mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__gte=now) \ No newline at end of file From 1f8bdd0461f8a80da21d72ecdb489f469b743bba Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 9 Sep 2024 10:48:53 +0800 Subject: [PATCH 085/106] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0wpm=20?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=88=86=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 70 ++++++++++++++++++++++++++++++++++++++++++----- apps/wpm/urls.py | 3 ++ 2 files changed, 66 insertions(+), 7 deletions(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index 11c0628e..c6d546ce 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -1,19 +1,75 @@ from apps.utils.viewsets import GenericViewSet from rest_framework.decorators import action from apps.em.models import Equipment -from apps.wpm.modes import Mlog +from apps.wpm.models import Mlog, Mlogb +from apps.mtm.models import Mgroup from django.utils import timezone +from django.db.models import Sum +from datetime import datetime, timedelta +from rest_framework.response import Response +from rest_framework.serializers import Serializer + +def tran_time_to_mstate(mstate_json, reminder_interval_list, work_start_time: datetime, now: datetime): + if len(reminder_interval_list) != len(mstate_json): + return '未运行' + for ind, val in enumerate(reminder_interval_list): + if work_start_time + timedelta(minutes=val) > now: + return mstate_json[ind] + return '未运行' class AnaViewSet(GenericViewSet): perms_map = {} - @action(methods=['post'], detail=False, perms_map={'post': '*'}) - def 设备最后生产日志(self, request): + @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer) + def equip_last_mlog(self, request): + """设备最后生产日志 + + 设备最后生产日志 + """ data = request.data now = timezone.now() - mgroup_name = data["mgroup_name"] + mgroup: Mgroup = Mgroup.objects.get(name=data['mgroup_name']) + # 子状态 + mstate_json = mgroup.process.mstate_json # 生产设备 - equip_qs = Equipment.objects.filter(mgroup__name=mgroup_name, type = 10) + equip_qs = Equipment.objects.filter(mgroup=mgroup, type = 10) + equip_qs_v = equip_qs.values('id', 'name', 'number', 'state').order_by('number') + equip_qs_l = list(equip_qs_v) # 设备最后生产日志 - mlog_qs = Mlog.objects.filter(equip__in=equip_qs) + mlog_qs = Mlog.objects.filter(equipment__in=equip_qs) mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__isnull=True) - mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__gte=now) \ No newline at end of file + mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__gte=now) + mlog_qs = mlog_qs.annotate(t_count_use=Sum('b_mlog__count_use')) + mlog_qs = mlog_qs.order_by('work_start_time') + mlog_qs_v = mlog_qs.values('id', 'equipment__id', 't_count_use', 'reminder_interval_list', 'work_start_time') + mlog_qs_l = list(mlog_qs_v) + mlog_dict = {item['equipment__id']: item for item in mlog_qs_l} + + # 统计数据 + 保温 = 0 + 冷却 = 0 + 未运行 = 0 + 故障 = 0 + now = timezone.now() + for item in equip_qs_l: + item['mstate'] = '未运行' + if item['id'] in mlog_dict: + item['t_count_use'] = mlog_dict[item['id']]['t_count_use'] + mlog_dict_v = mlog_dict[item['id']] + item['reminder_interval_list'] = mlog_dict_v['reminder_interval_list'] + item['mstate'] = tran_time_to_mstate(mstate_json, mlog_dict_v['reminder_interval_list'], mlog_dict_v['work_start_time'], now) + + if item['state'] in [Equipment.EQUIP_STATE_SCRAP, Equipment.EQUIP_STATE_FIX]: + item['mstate'] = '故障' + + if item['mstate'] == '保温': + 保温 += 1 + elif item['mstate'] == '冷却': + 冷却 += 1 + elif item['mstate'] == '未运行': + 未运行 += 1 + elif item['mstate'] == '故障': + 故障 += 1 + ret = {"保温": 保温, "冷却": 冷却, "未运行": 未运行, "故障": 故障} + ret["rows"] = equip_qs_l + return Response(ret) + diff --git a/apps/wpm/urls.py b/apps/wpm/urls.py index 3de12711..ec342726 100644 --- a/apps/wpm/urls.py +++ b/apps/wpm/urls.py @@ -5,6 +5,7 @@ from apps.wpm.views import (SfLogViewSet, StLogViewSet, SfLogExpViewSet, WMaterialViewSet, MlogViewSet, HandoverViewSet, AttlogViewSet, OtherLogViewSet, MlogbViewSet, MlogbInViewSet, MlogbOutViewSet, FmlogViewSet) +from apps.wpm.datax import AnaViewSet API_BASE_URL = 'api/wpm/' @@ -23,6 +24,8 @@ router.register('mlogb/out', MlogbOutViewSet) router.register('handover', HandoverViewSet, basename='handover') router.register('attlog', AttlogViewSet, basename='attlog') router.register('otherlog', OtherLogViewSet, basename='otherlog') +router.register('ana', AnaViewSet, basename='ana') + urlpatterns = [ path(API_BASE_URL, include(router.urls)), ] From d940c82e34c661530ba1275ba0f8bab1caa3d669 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 9 Sep 2024 13:21:42 +0800 Subject: [PATCH 086/106] fix: tran_time_to_mstate --- apps/wpm/datax.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index c6d546ce..7eadee1d 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -14,7 +14,7 @@ def tran_time_to_mstate(mstate_json, reminder_interval_list, work_start_time: da return '未运行' for ind, val in enumerate(reminder_interval_list): if work_start_time + timedelta(minutes=val) > now: - return mstate_json[ind] + return mstate_json[ind]['name'] return '未运行' class AnaViewSet(GenericViewSet): From 768f7a9a22eab7c7b4c6e7c5c285b9867248b678 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 9 Sep 2024 13:33:48 +0800 Subject: [PATCH 087/106] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84equip=5Flast?= =?UTF-8?q?=5Fmlog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index 7eadee1d..b10252e5 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -53,9 +53,10 @@ class AnaViewSet(GenericViewSet): for item in equip_qs_l: item['mstate'] = '未运行' if item['id'] in mlog_dict: - item['t_count_use'] = mlog_dict[item['id']]['t_count_use'] mlog_dict_v = mlog_dict[item['id']] + item['t_count_use'] = mlog_dict_v['t_count_use'] item['reminder_interval_list'] = mlog_dict_v['reminder_interval_list'] + item['work_start_time'] = mlog_dict_v['work_start_time'] item['mstate'] = tran_time_to_mstate(mstate_json, mlog_dict_v['reminder_interval_list'], mlog_dict_v['work_start_time'], now) if item['state'] in [Equipment.EQUIP_STATE_SCRAP, Equipment.EQUIP_STATE_FIX]: From 9ffe025ef7fd2246a9c0f06682731bda0455b15b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 9 Sep 2024 13:49:35 +0800 Subject: [PATCH 088/106] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84equip=5Flast?= =?UTF-8?q?=5Fmlog2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index b10252e5..6ade85d1 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -40,7 +40,7 @@ class AnaViewSet(GenericViewSet): mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__gte=now) mlog_qs = mlog_qs.annotate(t_count_use=Sum('b_mlog__count_use')) mlog_qs = mlog_qs.order_by('work_start_time') - mlog_qs_v = mlog_qs.values('id', 'equipment__id', 't_count_use', 'reminder_interval_list', 'work_start_time') + mlog_qs_v = mlog_qs.values('id', 'equipment__id', 't_count_use', 'reminder_interval_list', 'work_start_time', 'work_end_time') mlog_qs_l = list(mlog_qs_v) mlog_dict = {item['equipment__id']: item for item in mlog_qs_l} @@ -56,7 +56,8 @@ class AnaViewSet(GenericViewSet): mlog_dict_v = mlog_dict[item['id']] item['t_count_use'] = mlog_dict_v['t_count_use'] item['reminder_interval_list'] = mlog_dict_v['reminder_interval_list'] - item['work_start_time'] = mlog_dict_v['work_start_time'] + item['work_start_time'] = mlog_dict_v['work_start_time'].strftime('%Y-%m-%d %H:%M:%S') if mlog_dict_v['work_start_time'] else None + item['work_end_time'] = mlog_dict_v['work_end_time'].strftime('%Y-%m-%d %H:%M:%S') if mlog_dict_v['work_end_time'] else None item['mstate'] = tran_time_to_mstate(mstate_json, mlog_dict_v['reminder_interval_list'], mlog_dict_v['work_start_time'], now) if item['state'] in [Equipment.EQUIP_STATE_SCRAP, Equipment.EQUIP_STATE_FIX]: From 4d5195308f4c482ae9a21ff736db0bc89e1c173a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 9 Sep 2024 13:52:51 +0800 Subject: [PATCH 089/106] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84equip=5Flast?= =?UTF-8?q?=5Fmlog3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index 6ade85d1..aea4f723 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -72,6 +72,8 @@ class AnaViewSet(GenericViewSet): elif item['mstate'] == '故障': 故障 += 1 ret = {"保温": 保温, "冷却": 冷却, "未运行": 未运行, "故障": 故障} + ret['mstate_json'] = mstate_json + ret['now'] = now.strftime('%Y-%m-%d %H:%M:%S') ret["rows"] = equip_qs_l return Response(ret) From 1b6e947492f858d1acf80d57b6dbaf04e4db7f96 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 9 Sep 2024 14:01:57 +0800 Subject: [PATCH 090/106] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84equip=5Flast?= =?UTF-8?q?=5Fmlog4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index aea4f723..6ee8bad0 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -56,8 +56,8 @@ class AnaViewSet(GenericViewSet): mlog_dict_v = mlog_dict[item['id']] item['t_count_use'] = mlog_dict_v['t_count_use'] item['reminder_interval_list'] = mlog_dict_v['reminder_interval_list'] - item['work_start_time'] = mlog_dict_v['work_start_time'].strftime('%Y-%m-%d %H:%M:%S') if mlog_dict_v['work_start_time'] else None - item['work_end_time'] = mlog_dict_v['work_end_time'].strftime('%Y-%m-%d %H:%M:%S') if mlog_dict_v['work_end_time'] else None + item['work_start_time'] = timezone.localtime(mlog_dict_v['work_start_time']).strftime('%Y-%m-%d %H:%M:%S') if mlog_dict_v['work_start_time'] else None + item['work_end_time'] = timezone.localtime(mlog_dict_v['work_end_time']).strftime('%Y-%m-%d %H:%M:%S') if mlog_dict_v['work_end_time'] else None item['mstate'] = tran_time_to_mstate(mstate_json, mlog_dict_v['reminder_interval_list'], mlog_dict_v['work_start_time'], now) if item['state'] in [Equipment.EQUIP_STATE_SCRAP, Equipment.EQUIP_STATE_FIX]: @@ -73,7 +73,7 @@ class AnaViewSet(GenericViewSet): 故障 += 1 ret = {"保温": 保温, "冷却": 冷却, "未运行": 未运行, "故障": 故障} ret['mstate_json'] = mstate_json - ret['now'] = now.strftime('%Y-%m-%d %H:%M:%S') + ret['now'] = timezone.localtime(now).strftime('%Y-%m-%d %H:%M:%S') ret["rows"] = equip_qs_l return Response(ret) From 9a26529e0a35a355e9270958aaf5d1c16bcb954d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 9 Sep 2024 15:03:38 +0800 Subject: [PATCH 091/106] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84equip=5Flast?= =?UTF-8?q?=5Fmlog5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index 6ee8bad0..e0dab95a 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -1,7 +1,7 @@ from apps.utils.viewsets import GenericViewSet from rest_framework.decorators import action from apps.em.models import Equipment -from apps.wpm.models import Mlog, Mlogb +from apps.wpm.models import Mlog, Handover from apps.mtm.models import Mgroup from django.utils import timezone from django.db.models import Sum @@ -35,7 +35,7 @@ class AnaViewSet(GenericViewSet): equip_qs_v = equip_qs.values('id', 'name', 'number', 'state').order_by('number') equip_qs_l = list(equip_qs_v) # 设备最后生产日志 - mlog_qs = Mlog.objects.filter(equipment__in=equip_qs) + mlog_qs = Mlog.objects.filter(equipment__in=equip_qs, mgroup=mgroup) mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__isnull=True) mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__gte=now) mlog_qs = mlog_qs.annotate(t_count_use=Sum('b_mlog__count_use')) @@ -76,4 +76,19 @@ class AnaViewSet(GenericViewSet): ret['now'] = timezone.localtime(now).strftime('%Y-%m-%d %H:%M:%S') ret["rows"] = equip_qs_l return Response(ret) - + + @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer) + def put_prod(self, request): + """ + 投产分析 + """ + tomorrow = datetime.now() + timedelta(days=1) + for i in range(8): + timex = tomorrow - timedelta(days=i) + mgroup: Mgroup = Mgroup.objects.get(name='退火') + # 子状态 + mstate_json = mgroup.process.mstate_json + # 生产记录 + handover_qs = Handover.objects.filter(material__process=mgroup.process, send_mgroup=mgroup, type=Handover.H_NORMAL) + pass + From 1490a35a321bdccb8b7b7127d2302ad2e8b91e28 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 9 Sep 2024 16:44:25 +0800 Subject: [PATCH 092/106] =?UTF-8?q?feat:=20=E6=8A=95=E4=BA=A7=E5=88=86?= =?UTF-8?q?=E6=9E=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index e0dab95a..5843df32 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -8,6 +8,7 @@ from django.db.models import Sum from datetime import datetime, timedelta from rest_framework.response import Response from rest_framework.serializers import Serializer +from apps.inm.models import MIOItem, MIO def tran_time_to_mstate(mstate_json, reminder_interval_list, work_start_time: datetime, now: datetime): if len(reminder_interval_list) != len(mstate_json): @@ -35,9 +36,8 @@ class AnaViewSet(GenericViewSet): equip_qs_v = equip_qs.values('id', 'name', 'number', 'state').order_by('number') equip_qs_l = list(equip_qs_v) # 设备最后生产日志 - mlog_qs = Mlog.objects.filter(equipment__in=equip_qs, mgroup=mgroup) - mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__isnull=True) - mlog_qs = mlog_qs | Mlog.objects.filter(work_start_time__lte=now, work_end_time__gte=now) + mlog_qs_0 = Mlog.objects.filter(equipment__in=equip_qs, mgroup=mgroup) + mlog_qs = mlog_qs_0.exclude(work_end_time__lt=now) mlog_qs = mlog_qs.annotate(t_count_use=Sum('b_mlog__count_use')) mlog_qs = mlog_qs.order_by('work_start_time') mlog_qs_v = mlog_qs.values('id', 'equipment__id', 't_count_use', 'reminder_interval_list', 'work_start_time', 'work_end_time') @@ -82,13 +82,40 @@ class AnaViewSet(GenericViewSet): """ 投产分析 """ - tomorrow = datetime.now() + timedelta(days=1) - for i in range(8): - timex = tomorrow - timedelta(days=i) + now = timezone.now() + tomorrow = now + timedelta(days=1) + now_2 = now.replace(hour=2, minute=0, second=0, microsecond=0) + timex_2 = tomorrow.replace(hour=2, minute=0, second=0, microsecond=0) + timex_8_ago = timex_2 - timedelta(days=8) mgroup: Mgroup = Mgroup.objects.get(name='退火') # 子状态 mstate_json = mgroup.process.mstate_json - # 生产记录 - handover_qs = Handover.objects.filter(material__process=mgroup.process, send_mgroup=mgroup, type=Handover.H_NORMAL) - pass + ret = {} + ret['今日退火投产预测'] = 0 + ret['明日退火投产预测'] = 0 + ret['rows'] = {} + # 生产记录/今日退火投产预测 + # 昨日2点 + now_2_yesterday = now_2 - timedelta(days=1) + + mlog_qs_0 = Mlog.objects.filter(mgroup=mgroup) + mlog_qs = mlog_qs_0.exclude(work_end_time__lt=now_2_yesterday).annotate(t_count_use=Sum('b_mlog__count_use')).order_by('work_start_time') + mlog_qs_v = mlog_qs.values('id', 'equipment__id', 't_count_use', 'reminder_interval_list', 'work_start_time', 'work_end_time') + mlog_qs_l = list(mlog_qs_v) + + for item in mlog_qs_l: + if tran_time_to_mstate(mstate_json, item['reminder_interval_list'], item['work_start_time'], now) == '冷却': + if item['work_end_time'] is None or item['work_end_time'] > now_2: + ret['明日退火投产预测'] += item['t_count_use'] + ret['今日退火投产预测'] += item['t_count_use'] + return ret + # # 交接记录 + # handover_qs = Handover.objects.filter(material__process=mgroup.process, send_mgroup=mgroup, type=Handover.H_NORMAL, + # submit_time__range=[timex_8_ago, timex_2]).values('id', 'submit_time', 'count') + # handover_qs_l = list(handover_qs) + + # # 生产入库 + # mioitem_qs = MIOItem.objects.filter(mio__mgroup=mgroup, material__process=mgroup.process, mio__type=MIO.MIO_TYPE_DO_IN, + # mio__submit_time__range=[timex_8_ago, timex_2]).values('id', 'mio__submit_time', 'count') + From f3c31a5b39931b9ffa89532af94136d97faf6bfc Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 10 Sep 2024 08:50:30 +0800 Subject: [PATCH 093/106] =?UTF-8?q?feat:=20=E6=8A=95=E4=BA=A7=E5=88=86?= =?UTF-8?q?=E6=9E=90=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/datax.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index 5843df32..eb52d7c2 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -83,10 +83,7 @@ class AnaViewSet(GenericViewSet): 投产分析 """ now = timezone.now() - tomorrow = now + timedelta(days=1) now_2 = now.replace(hour=2, minute=0, second=0, microsecond=0) - timex_2 = tomorrow.replace(hour=2, minute=0, second=0, microsecond=0) - timex_8_ago = timex_2 - timedelta(days=8) mgroup: Mgroup = Mgroup.objects.get(name='退火') # 子状态 mstate_json = mgroup.process.mstate_json @@ -109,13 +106,5 @@ class AnaViewSet(GenericViewSet): ret['明日退火投产预测'] += item['t_count_use'] ret['今日退火投产预测'] += item['t_count_use'] - return ret - # # 交接记录 - # handover_qs = Handover.objects.filter(material__process=mgroup.process, send_mgroup=mgroup, type=Handover.H_NORMAL, - # submit_time__range=[timex_8_ago, timex_2]).values('id', 'submit_time', 'count') - # handover_qs_l = list(handover_qs) - - # # 生产入库 - # mioitem_qs = MIOItem.objects.filter(mio__mgroup=mgroup, material__process=mgroup.process, mio__type=MIO.MIO_TYPE_DO_IN, - # mio__submit_time__range=[timex_8_ago, timex_2]).values('id', 'mio__submit_time', 'count') + return Response(ret) From 18fe3466615558dcb548a444c27b65b6013e27db Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 10 Sep 2024 15:12:14 +0800 Subject: [PATCH 094/106] fix: tran_time_to_mstate --- apps/wpm/datax.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index eb52d7c2..2637fa14 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -13,8 +13,10 @@ from apps.inm.models import MIOItem, MIO def tran_time_to_mstate(mstate_json, reminder_interval_list, work_start_time: datetime, now: datetime): if len(reminder_interval_list) != len(mstate_json): return '未运行' + xval = 0 for ind, val in enumerate(reminder_interval_list): - if work_start_time + timedelta(minutes=val) > now: + xval += val + if work_start_time + timedelta(minutes=xval) > now: return mstate_json[ind]['name'] return '未运行' From 082619070e4fb6b5722ddf034efef515cf479387 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 10 Sep 2024 17:06:56 +0800 Subject: [PATCH 095/106] =?UTF-8?q?feat:=20handover=E5=A2=9E=E5=8A=A0dept?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9D=A1=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/filters.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index c2addaea..3fbe989e 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -73,9 +73,13 @@ class MlogFilter(filters.FilterSet): class HandoverFilter(filters.FilterSet): mgroup = filters.CharFilter(label='MgroupId', method='filter_mgroup') + dept = filters.CharFilter(label='DeptId', method='filter_dept') def filter_mgroup(self, queryset, name, value): return queryset.filter(send_mgroup__id=value)|queryset.filter(recive_mgroup__id=value) + + def filter_belong_dept(self, queryset, name, value): + return queryset.filter(send_dept__id=value)|queryset.filter(recive_dept__id=value) class Meta: model = Handover From ca2103db8ed245d213936b593011a3d2b4eea144 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 10 Sep 2024 17:38:35 +0800 Subject: [PATCH 096/106] =?UTF-8?q?fix:=20handover=E5=A2=9E=E5=8A=A0dept?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E6=9D=A1=E4=BB=B6?= 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 3fbe989e..22ecd9ef 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -78,7 +78,7 @@ class HandoverFilter(filters.FilterSet): def filter_mgroup(self, queryset, name, value): return queryset.filter(send_mgroup__id=value)|queryset.filter(recive_mgroup__id=value) - def filter_belong_dept(self, queryset, name, value): + def filter_dept(self, queryset, name, value): return queryset.filter(send_dept__id=value)|queryset.filter(recive_dept__id=value) class Meta: From 1caba24321943c81d3f42bb66fb4357f5da016a3 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 11 Sep 2024 16:20:34 +0800 Subject: [PATCH 097/106] =?UTF-8?q?feat:=20ftestwork=20belong=5Fdept?= =?UTF-8?q?=E9=BB=98=E8=AE=A4test=5Fuser=20=E6=89=80=E5=9C=A8=E9=83=A8?= =?UTF-8?q?=E9=97=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/filters.py | 2 +- apps/qm/serializers.py | 2 ++ apps/wpm/datax.py | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/apps/qm/filters.py b/apps/qm/filters.py index e2c1d069..1ac42ff8 100644 --- a/apps/qm/filters.py +++ b/apps/qm/filters.py @@ -34,5 +34,5 @@ class FtestWorkFilter(filters.FilterSet): "mb": ["exact"], "batch": ["exact"], "type": ["exact"], - "type2": ["exact"], + "type2": ["exact"], } \ No newline at end of file diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index b5f941c2..ddde6b20 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -96,6 +96,8 @@ class FtestWorkCreateUpdateSerializer(CustomModelSerializer): attrs['batch'] = attrs['mb'].batch else: raise ValidationError('请选择车间/仓库库存') + if attrs['test_user']: + attrs['belong_dept'] = attrs['test_user'].belong_dept return attrs diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index 2637fa14..560b808a 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -110,3 +110,7 @@ class AnaViewSet(GenericViewSet): return Response(ret) + perms_map = {} + @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer) + def equip_last_mlog(self, request): + pass From bc92e907658d1231afcb3c906e4b21f66843d8d1 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 11 Sep 2024 16:39:09 +0800 Subject: [PATCH 098/106] =?UTF-8?q?feat:=20ftestwork=20=E5=A2=9E=E5=8A=A0s?= =?UTF-8?q?hift=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/filters.py | 3 ++- apps/qm/migrations/0024_ftestwork_shift.py | 20 ++++++++++++++++++++ apps/qm/models.py | 3 ++- apps/qm/serializers.py | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 apps/qm/migrations/0024_ftestwork_shift.py diff --git a/apps/qm/filters.py b/apps/qm/filters.py index 1ac42ff8..162c793e 100644 --- a/apps/qm/filters.py +++ b/apps/qm/filters.py @@ -34,5 +34,6 @@ class FtestWorkFilter(filters.FilterSet): "mb": ["exact"], "batch": ["exact"], "type": ["exact"], - "type2": ["exact"], + "type2": ["exact"], + "shift": ["exact"] } \ No newline at end of file diff --git a/apps/qm/migrations/0024_ftestwork_shift.py b/apps/qm/migrations/0024_ftestwork_shift.py new file mode 100644 index 00000000..7743caaa --- /dev/null +++ b/apps/qm/migrations/0024_ftestwork_shift.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.12 on 2024-09-11 08:28 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0041_process_mstate_json'), + ('qm', '0023_ftestwork_need_update_wm'), + ] + + operations = [ + migrations.AddField( + model_name='ftestwork', + name='shift', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='mtm.shift', verbose_name='班次'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index 3501ae2e..d69b2854 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -1,7 +1,7 @@ from django.db import models from apps.system.models import CommonAModel, CommonADModel, User from apps.utils.models import CommonBDModel, BaseModel -from apps.mtm.models import Material, Mgroup, Team +from apps.mtm.models import Material, Mgroup, Team, Shift from apps.wpm.models import SfLog, WMaterial from django.utils.translation import gettext_lazy as _ @@ -111,6 +111,7 @@ class FtestWork(CommonBDModel): """ type = models.CharField('检验类型', max_length=20, choices=FTEST_TYPE_CHOICES, default='prod') type2 = models.PositiveSmallIntegerField('检验类型2', choices=((10, '抽检'), (20, '全检')), default=10) + shift = models.ForeignKey(Shift, verbose_name='班次', on_delete=models.SET_NULL, null=True, blank=True) wm = models.ForeignKey(WMaterial, verbose_name='关联车间库存', on_delete=models.SET_NULL, null=True, blank=True) mb = models.ForeignKey('inm.materialbatch', verbose_name='关联仓库', on_delete=models.SET_NULL, null=True, blank=True) test_date = models.DateField('检验日期') diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index ddde6b20..68a8b368 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -63,7 +63,7 @@ class QuaStatUpdateSerializer(CustomModelSerializer): class FtestWorkCreateUpdateSerializer(CustomModelSerializer): class Meta: model = FtestWork - fields = ['id', 'wm', 'mb', 'type', 'type2', 'test_date', 'count', 'count_sampling', 'count_sampling_ok', 'count_ok', 'count_notok', 'count_notok_json', 'test_user', 'need_update_wm'] + fields = ['id', 'shift', 'wm', 'mb', 'type', 'type2', 'test_date', 'count', 'count_sampling', 'count_sampling_ok', 'count_ok', 'count_notok', 'count_notok_json', 'test_user', 'need_update_wm'] extra_kwargs = {'test_user': {'required': True}, 'type': {'required': True}} def validate(self, attrs): From 7a8bee5e59d45c00d246fc5fe648f32bed80e6a5 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 12 Sep 2024 11:19:00 +0800 Subject: [PATCH 099/106] =?UTF-8?q?feat:=20wmaterial=E5=A2=9E=E5=8A=A0coun?= =?UTF-8?q?t=5Fworking=20proptey?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/models.py | 4 ++++ apps/wpm/serializers.py | 1 + 2 files changed, 5 insertions(+) diff --git a/apps/wpm/models.py b/apps/wpm/models.py index 4500fb6a..c5c7e53c 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -8,6 +8,7 @@ from apps.em.models import Equipment from apps.system.models import Dept from datetime import timedelta from apps.pum.models import Supplier +from django.db.models import Sum # Create your models here. @@ -106,6 +107,9 @@ class WMaterial(CommonBDModel): material_origin = models.ForeignKey(Material, verbose_name='原始物料', on_delete=models.SET_NULL, null=True, blank=True, related_name='wm_mo') count_xtest = models.PositiveIntegerField('已检数量', null=True, blank=True) + @property + def count_working(self, obj): + return Mlogb.objects.filter(wm_in=obj, mlog__work_end_time__isnull=True).aggregate(count=Sum('count'))['count'] or 0 class Fmlog(CommonADModel): route = models.ForeignKey(Route, verbose_name='生产路线', on_delete=models.SET_NULL, null=True, blank=True) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index 5611e42c..a468824b 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -181,6 +181,7 @@ class WMaterialSerializer(CustomModelSerializer): source='belong_dept.name', read_only=True) material_origin_name = serializers.StringRelatedField(source='material_origin', read_only=True) notok_sign_name = serializers.SerializerMethodField() + count_working = serializers.CharField(read_only=True, label='在制数量') def get_notok_sign_name(self, obj): return getattr(NotOkOption, obj.notok_sign, NotOkOption.qt).label if obj.notok_sign else None From de42dfc75fbee01e3a63ba710eb86cece5ab5239 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 12 Sep 2024 11:24:56 +0800 Subject: [PATCH 100/106] =?UTF-8?q?fix:=20wmaterial=20=E8=BF=94=E5=9B=9Eco?= =?UTF-8?q?unt=5Fworking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/wpm/models.py b/apps/wpm/models.py index c5c7e53c..55b01cf0 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -108,8 +108,8 @@ class WMaterial(CommonBDModel): count_xtest = models.PositiveIntegerField('已检数量', null=True, blank=True) @property - def count_working(self, obj): - return Mlogb.objects.filter(wm_in=obj, mlog__work_end_time__isnull=True).aggregate(count=Sum('count'))['count'] or 0 + def count_working(self): + return Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count'))['count'] or 0 class Fmlog(CommonADModel): route = models.ForeignKey(Route, verbose_name='生产路线', on_delete=models.SET_NULL, null=True, blank=True) From 8f0e512654793615865413820400bc717f5ff54a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 12 Sep 2024 11:26:39 +0800 Subject: [PATCH 101/106] =?UTF-8?q?fix:=20wmaterial=20=E8=BF=94=E5=9B=9Eco?= =?UTF-8?q?unt=5Fworking?= 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 55b01cf0..4a02cddf 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -109,7 +109,7 @@ class WMaterial(CommonBDModel): @property def count_working(self): - return Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count'))['count'] or 0 + return Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count_use'))['count'] or 0 class Fmlog(CommonADModel): route = models.ForeignKey(Route, verbose_name='生产路线', on_delete=models.SET_NULL, null=True, blank=True) From 2d79796ccb6c843e9b370e3be93c01b045c69fef Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 12 Sep 2024 11:29:43 +0800 Subject: [PATCH 102/106] =?UTF-8?q?fix:=20wmaterial=20=E8=BF=94=E5=9B=9Eco?= =?UTF-8?q?unt=5Fworking2?= 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 4a02cddf..61985ea9 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -109,7 +109,7 @@ class WMaterial(CommonBDModel): @property def count_working(self): - return Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count_use'))['count'] or 0 + return int(Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count_use'))['count']) or 0 class Fmlog(CommonADModel): route = models.ForeignKey(Route, verbose_name='生产路线', on_delete=models.SET_NULL, null=True, blank=True) From 28e5b83896649d9c9e426045cff77b715ca19bdf Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 12 Sep 2024 11:31:08 +0800 Subject: [PATCH 103/106] =?UTF-8?q?fix:=20wmaterial=20=E8=BF=94=E5=9B=9Eco?= =?UTF-8?q?unt=5Fworking3?= 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 61985ea9..34b91399 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -109,7 +109,7 @@ class WMaterial(CommonBDModel): @property def count_working(self): - return int(Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count_use'))['count']) or 0 + return int(Mlogb.objects.filter(wm_in=self, mlog__work_end_time__isnull=True).aggregate(count=Sum('count_use'))['count'] or 0) class Fmlog(CommonADModel): route = models.ForeignKey(Route, verbose_name='生产路线', on_delete=models.SET_NULL, null=True, blank=True) From 2753c78997025090ece3e269dc1f26af17ec54f7 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 12 Sep 2024 15:23:38 +0800 Subject: [PATCH 104/106] =?UTF-8?q?feat:=20bi=E6=9F=A5=E8=AF=A2=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E5=90=8E=E6=89=93=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/bi/views.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/bi/views.py b/apps/bi/views.py index 411657bc..6321fe40 100644 --- a/apps/bi/views.py +++ b/apps/bi/views.py @@ -12,6 +12,8 @@ from apps.bi.services import check_sql_safe, format_json_with_placeholders from rest_framework.exceptions import ParseError from rest_framework.generics import get_object_or_404 from apps.utils.mixins import ListModelMixin +import logging +myLogger = logging.getLogger('log') # Create your views here. @@ -101,6 +103,7 @@ class DatasetViewSet(CustomModelViewSet): results[name], results2[name] = format_sqldata( res[0], res[1]) except Exception as e: + myLogger.error(f'bi查询异常:{str(e)}-{dt.code}--{sql_f}') if raise_exception: raise ParseError(f'查询异常:{str(e)}') else: From bc6406f12bcd8d915bd4d4f948535267a1ea1b8f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 12 Sep 2024 17:23:40 +0800 Subject: [PATCH 105/106] fix: ana equip_last_mlog --- apps/wpm/datax.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/apps/wpm/datax.py b/apps/wpm/datax.py index 560b808a..48f37bf6 100644 --- a/apps/wpm/datax.py +++ b/apps/wpm/datax.py @@ -108,9 +108,4 @@ class AnaViewSet(GenericViewSet): ret['明日退火投产预测'] += item['t_count_use'] ret['今日退火投产预测'] += item['t_count_use'] - return Response(ret) - - perms_map = {} - @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=Serializer) - def equip_last_mlog(self, request): - pass + return Response(ret) \ No newline at end of file From f51bb48428614031c4ea63040cdcd2d7dedc2601 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 13 Sep 2024 12:53:55 +0800 Subject: [PATCH 106/106] =?UTF-8?q?feat:=20handover=20serializer=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/wpm/serializers.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/wpm/serializers.py b/apps/wpm/serializers.py index a468824b..f84ee9fa 100644 --- a/apps/wpm/serializers.py +++ b/apps/wpm/serializers.py @@ -624,12 +624,14 @@ class HandoverSerializer(CustomModelSerializer): attrs['batch'] = wm.batch elif handoverb: wm: WMaterial = handoverb[0]["wm"] + if wm: + pass else: raise ParseError('必须指定车间库存') attrs['material'] = wm.material attrs['send_dept'] = wm.belong_dept - if handoverb[0]["wm"].mgroup: - attrs['send_mgroup'] = handoverb[0]["wm"].mgroup + if wm.mgroup: + attrs['send_mgroup'] = wm.mgroup if attrs['material'].process and attrs['material'].process.into_wm_mgroup and 'recive_mgroup' not in attrs: raise ValidationError('必须指定交接工段') if 'recive_mgroup' in attrs and attrs['recive_mgroup']: @@ -642,6 +644,8 @@ class HandoverSerializer(CustomModelSerializer): for ind, item in enumerate(attrs['handoverb']): wm = item["wm"] t_count += item["count"] + if wm.mgroup != attrs['send_mgroup']: + raise ParseError(f'第{ind+1}物料与交接工段不一致') if attrs["material"] != wm.material: raise ParseError(f'第{ind+1}物料与交接物料不一致') if wm.notok_sign is not None and attrs['type'] in [Handover.H_NORMAL, Handover.H_TEST]: