diff --git a/apps/cm/filters.py b/apps/cm/filters.py new file mode 100644 index 00000000..4cdbe3d5 --- /dev/null +++ b/apps/cm/filters.py @@ -0,0 +1,11 @@ +from django_filters import rest_framework as filters +from django.utils import timezone +from .models import LabelTemplate +from apps.utils.filters import MyJsonListFilter + +class LabelTemplateFilter(filters.FilterSet): + process = MyJsonListFilter(label='按工序查询', field_name="process_json") + + class Meta: + model = LabelTemplate + fields = ['process', "name"] \ No newline at end of file diff --git a/apps/cm/migrations/0005_labeltemplate_process_json.py b/apps/cm/migrations/0005_labeltemplate_process_json.py new file mode 100644 index 00000000..e296d3ec --- /dev/null +++ b/apps/cm/migrations/0005_labeltemplate_process_json.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2025-05-06 02:25 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('cm', '0004_labeltemplate'), + ] + + operations = [ + migrations.AddField( + model_name='labeltemplate', + name='process_json', + field=models.JSONField(blank=True, default=list, verbose_name='工序'), + ), + ] diff --git a/apps/cm/models.py b/apps/cm/models.py index 3329dcfe..f2e22728 100644 --- a/apps/cm/models.py +++ b/apps/cm/models.py @@ -3,6 +3,7 @@ from apps.utils.models import BaseModel from apps.mtm.models import Material from apps.pum.models import Supplier from apps.wpm.models import WmStateOption +from rest_framework.exceptions import NotFound, ParseError # Create your models here. class LableMat(BaseModel): @@ -17,5 +18,25 @@ class LableMat(BaseModel): class LabelTemplate(BaseModel): + """TN: 标签模板""" name = models.TextField("名称") - commands = models.JSONField("指令模板", default=list, blank=True) \ No newline at end of file + commands = models.JSONField("指令模板", default=list, blank=True) + process_json = models.JSONField("工序", default=list, blank=True) + + @classmethod + def gen_commands(cls, label_template, label_template_name, tdata): + if label_template: + lt = LabelTemplate.objects.get(id=label_template) + else: + lt = LabelTemplate.objects.filter(name=label_template_name).first() + if not lt: + raise NotFound("标签模板不存在") + commands:list = lt.commands + try: + n_commands = [] + for item in commands: + item = item.format(**tdata) + n_commands.append(item) + except Exception as e: + raise ParseError(f"标签解析错误-{str(e)}") + return n_commands \ No newline at end of file diff --git a/apps/cm/serializers.py b/apps/cm/serializers.py index 075c7f0f..5ccbfc51 100644 --- a/apps/cm/serializers.py +++ b/apps/cm/serializers.py @@ -7,6 +7,14 @@ from apps.utils.serializers import CustomModelSerializer class TidSerializer(serializers.Serializer): tid = serializers.CharField(label='表ID') + label_template = serializers.CharField(label='标签模板ID', allow_null=True, required=False) + label_template_name = serializers.CharField(label='标签模板名称', allow_null=True, required=False) + extra_data = serializers.JSONField(label='额外数据', allow_null=True, required=False) + +class Tid2Serializer(serializers.Serializer): + label_template = serializers.CharField(label='标签模板ID', allow_null=True, required=False) + label_template_name = serializers.CharField(label='标签模板名称', allow_null=True, required=False) + data = serializers.JSONField(label='数据', allow_null=True, required=False) class LabelMatSerializer(serializers.ModelSerializer): diff --git a/apps/cm/views.py b/apps/cm/views.py index 2ab8c35d..92c30a6a 100644 --- a/apps/cm/views.py +++ b/apps/cm/views.py @@ -1,11 +1,12 @@ from apps.cm.models import LableMat, LabelTemplate from rest_framework.decorators import action -from apps.cm.serializers import TidSerializer, LabelMatSerializer, LabelTemplateSerializer +from apps.cm.serializers import TidSerializer, LabelMatSerializer, LabelTemplateSerializer, Tid2Serializer from apps.inm.models import MaterialBatch, MIOItem from apps.wpm.models import WMaterial from rest_framework.exceptions import ParseError, NotFound from rest_framework.response import Response from apps.utils.viewsets import CustomGenericViewSet, RetrieveModelMixin, CustomListModelMixin, CustomModelViewSet +from apps.cm.filters import LabelTemplateFilter # Create your views here. SPLIT_FIELD = "#" @@ -24,6 +25,9 @@ class LableMatViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericVie 从仓库明细获取物料标签 """ tid = request.data.get("tid") + label_template = request.data.get("label_template", None) + label_template_name = request.data.get("label_template_name", None) + extra_data = request.data.get("extra_data", {}) try: mb = MaterialBatch.objects.get(id=tid) except MaterialBatch.DoesNotExist: @@ -31,6 +35,10 @@ class LableMatViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericVie obj, _ = LableMat.objects.get_or_create(state=mb.state, material=mb.material, batch=mb.batch, defect=mb.defect, defaults={"supplier": mb.supplier}) rdata = LabelMatSerializer(obj).data rdata["code_label"] = f"mat{SPLIT_FIELD}{obj.id}" + if label_template or label_template_name: + tdata = {**rdata, **extra_data} + commands = LabelTemplate.gen_commands(label_template, label_template_name, tdata) + rdata["commands"] = commands return Response(rdata) @action(methods=["post"], detail=False, serializer_class=TidSerializer) @@ -41,6 +49,9 @@ class LableMatViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericVie 从车间库存明细获取物料标签 """ tid = request.data.get("tid") + label_template = request.data.get("label_template", None) + label_template_name = request.data.get("label_template_name", None) + extra_data = request.data.get("extra_data", {}) try: wm = WMaterial.objects.get(id=tid) except WMaterial.DoesNotExist: @@ -50,6 +61,10 @@ class LableMatViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericVie material_origin=wm.material_origin) rdata = LabelMatSerializer(obj).data rdata["code_label"] = f"mat{SPLIT_FIELD}{obj.id}" + if label_template or label_template_name: + tdata = {**rdata, **extra_data} + commands = LabelTemplate.gen_commands(label_template, label_template_name, tdata) + rdata["commands"] = commands return Response(rdata) @action(methods=["post"], detail=False, serializer_class=TidSerializer) @@ -60,6 +75,9 @@ class LableMatViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericVie 从出入库明细获取物料标签 """ tid = request.data.get("tid") + label_template = request.data.get("label_template", None) + label_template_name = request.data.get("label_template_name", None) + extra_data = request.data.get("extra_data", {}) try: mioitem: MIOItem = MIOItem.objects.get(id=tid) except MIOItem.DoesNotExist: @@ -67,6 +85,10 @@ class LableMatViewSet(CustomListModelMixin, RetrieveModelMixin, CustomGenericVie obj, _ = LableMat.objects.get_or_create(state=10, material=mioitem.material, batch=mioitem.batch, defaults={"supplier": mioitem.mio.supplier}) rdata = LabelMatSerializer(obj).data rdata["code_label"] = f"mat{SPLIT_FIELD}{obj.id}" + if label_template or label_template_name: + tdata = {**rdata, **extra_data} + commands = LabelTemplate.gen_commands(label_template, label_template_name, tdata) + rdata["commands"] = commands return Response(rdata) @@ -77,4 +99,18 @@ class LabelTemplateViewSet(CustomModelViewSet): 标签模板 """ queryset = LabelTemplate.objects.all() - serializer_class = LabelTemplateSerializer \ No newline at end of file + serializer_class = LabelTemplateSerializer + filterset_class = LabelTemplateFilter + + @action(methods=["post"], detail=False, serializer_class=Tid2Serializer) + def commands(self, request, *args, **kwargs): + """ + 获取标签指令 + + 获取标签指令 + """ + label_template = request.data.get("label_template", None) + label_template_name = request.data.get("label_template_name", None) + data = request.data.get("data", {}) + return Response({"commands": LabelTemplate.gen_commands(label_template, label_template_name, data)}) + \ No newline at end of file diff --git a/apps/develop/views.py b/apps/develop/views.py index 893b9cda..3dd2d692 100755 --- a/apps/develop/views.py +++ b/apps/develop/views.py @@ -616,14 +616,14 @@ class TestViewSet(CustomGenericViewSet): 'apps.rpm.tasks.close_rpj_by_leave_time']).delete() if 'mes' in datas: from apps.inm.models import MaterialBatch, MIO - from apps.mtm.models import Material + from apps.mtm.models import Material, RoutePack from apps.wpmw.models import Wpr - from apps.wpm.models import WMaterial, Mlog + from apps.wpm.models import WMaterial, Mlog, Handover, BatchSt from apps.pum.models import PuOrder from apps.sam.models import Order from apps.pm.models import Utask, Mtask - from apps.wpm.models import Handover from apps.qm.models import Ftest, FtestWork + from apps.wf.models import Ticket MaterialBatch.objects.all().delete() MIO.objects.all().delete() Wpr.objects.all().delete() @@ -636,7 +636,9 @@ class TestViewSet(CustomGenericViewSet): Handover.objects.all().delete() Ftest.objects.all().delete() FtestWork.objects.all().delete() - Material.objects.all().update(count=0, count_mb=0, count_wm=0) + Material.objects.get_queryset(all=True).update(count=0, count_mb=0, count_wm=0) + BatchSt.objects.all().delete() + Ticket.objects.get_queryset(all=True).delete() return Response() @action(methods=['post'], detail=False, serializer_class=Serializer, permission_classes=[]) diff --git a/apps/inm/views.py b/apps/inm/views.py index 51fe7854..f9d1c1a9 100644 --- a/apps/inm/views.py +++ b/apps/inm/views.py @@ -254,6 +254,7 @@ class MIOItemViewSet(CustomListModelMixin, BulkCreateModelMixin, BulkDestroyMode "test_date": ["isnull", "exact"] } ordering = ['create_time'] + ordering_fields = ['create_time', 'test_date'] def add_info_for_list(self, data): diff --git a/apps/utils/filters.py b/apps/utils/filters.py index 0e950877..18baa0ef 100755 --- a/apps/utils/filters.py +++ b/apps/utils/filters.py @@ -3,13 +3,16 @@ from django_filters import rest_framework as filters class MyJsonListFilter(filters.CharFilter): def filter(self, qs, value): + if value in ['all', '']: return qs elif ',' in value: value_l = value.split(',') qsx = qs.none() for i in value_l: - qsx = qsx | qs.filter(tags__contains=i) + kv = {f"{self.field_name}__contains": i} + qsx = qsx | qs.filter(**kv) return qsx else: - return qs.filter(tags__contains=value) + kv = {f"{self.field_name}__contains": value} + return qs.filter(**kv) diff --git a/apps/utils/sms.py b/apps/utils/sms.py index 19616381..7e3d85bb 100644 --- a/apps/utils/sms.py +++ b/apps/utils/sms.py @@ -4,6 +4,7 @@ import json import logging from server.settings import get_sysconfig from apps.utils.decorators import auto_log +from rest_framework.exceptions import ParseError # 实例化myLogger myLogger = logging.getLogger('log') @@ -12,8 +13,8 @@ myLogger = logging.getLogger('log') @auto_log(name='阿里云短信', raise_exception=True, send_mail=True) def send_sms(phone: str, template_code: int, template_param: dict): config = get_sysconfig() - if config.get("sms", {}).get('enabled', True) is False: - return + if config.get("sms", {}).get('enabled', False) is False: + raise ParseError("短信发送功能未启用") try: client = AcsClient(config['sms']['xn_key'], config['sms']['xn_secret'], 'default') diff --git a/apps/wpm/filters.py b/apps/wpm/filters.py index a4a17fc4..c698d8e4 100644 --- a/apps/wpm/filters.py +++ b/apps/wpm/filters.py @@ -178,9 +178,11 @@ class BatchStFilter(filters.FilterSet): model = BatchSt fields = { "batch": ["exact", "contains", "startswith"], + "first_time": ["exact", "gte", "lte"], "last_time": ["exact", "gte", "lte"], "update_time": ["exact", "gte", "lte"], "material_start": ["exact"], + "material_start__cate": ["exact"], "material_start__type": ["exact"], "material_start__process": ["exact"] } diff --git a/apps/wpm/migrations/0115_batchst_first_time.py b/apps/wpm/migrations/0115_batchst_first_time.py new file mode 100644 index 00000000..aef50426 --- /dev/null +++ b/apps/wpm/migrations/0115_batchst_first_time.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2025-05-08 08:23 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0114_auto_20250428_1350'), + ] + + operations = [ + migrations.AddField( + model_name='batchst', + name='first_time', + field=models.DateTimeField(blank=True, null=True, verbose_name='首次操作时间'), + ), + ] diff --git a/apps/wpm/models.py b/apps/wpm/models.py index f6e306dd..cc344e1a 100644 --- a/apps/wpm/models.py +++ b/apps/wpm/models.py @@ -609,6 +609,7 @@ class BatchSt(BaseModel): """ batch = models.TextField("批次号", db_index=True) version = models.IntegerField("版本号", default=1, db_index=True) + first_time = models.DateTimeField("首次操作时间", null=True, blank=True) last_time = models.DateTimeField("最后操作时间", null=True, blank=True) data = models.JSONField("数据", default=list, blank=True) material_start = models.ForeignKey(Material, verbose_name="起始物料", on_delete=models.SET_NULL, null=True, blank=True) diff --git a/apps/wpm/scripts/batch_gxerp.py b/apps/wpm/scripts/batch_gxerp.py new file mode 100644 index 00000000..eb3116f1 --- /dev/null +++ b/apps/wpm/scripts/batch_gxerp.py @@ -0,0 +1,95 @@ +from apps.wpm.models import BatchSt +import logging +from apps.qm.models import Defect +from apps.wpm.models import Mlogb, MlogbDefect +import decimal +from django.db.models import Sum + +myLogger = logging.getLogger("log") + +def main(batch: str): + try: + batchst = BatchSt.objects.get(batch=batch, version=1) + except BatchSt.DoesNotExist: + myLogger.error(f"Batch {batch} does not exist") + return None, None + + data = {"批次号": batch} + + mgroup_names = ["尺寸检验", "外观检验"] + for mgroup_name in mgroup_names: + mlogb1_qs = Mlogb.objects.filter(mlog__submit_time__isnull=False, material_out__isnull=False, mlog__mgroup__name=mgroup_name, batch=batch) + if mlogb1_qs.exists(): + data[f"{mgroup_name}_日期"] = [] + data[f"{mgroup_name}_操作人"] = [] + data[f"{mgroup_name}_count_real"] = 0 + data[f"{mgroup_name}_count_ok"] = 0 + data[f"{mgroup_name}_count_ok_full"] = 0 + for item in mlogb1_qs: + if item.mlog.handle_user: + data[f"{mgroup_name}_操作人"].append(item.mlog.handle_user) + if item.mlog.handle_date: + data[f"{mgroup_name}_日期"].append(item.mlog.handle_date) + data[f"{mgroup_name}_count_real"] += item.count_real + data[f"{mgroup_name}_count_ok"] += item.count_ok + data[f"{mgroup_name}_count_ok_full"] += item.count_ok_full + + try: + data[f"{mgroup_name}_合格率"] = round((data[f"{mgroup_name}-count_ok"] / data[f"{mgroup_name}-count_real"])*100, 2) + except decimal.InvalidOperation: + data[f"{mgroup_name}_合格率"] = 0 + + mlogbd1_qs = MlogbDefect.objects.filter(mlogb__in=mlogb1_qs, count__gt=0).values("defect__name").annotate(total=Sum("count")) + + for item in mlogbd1_qs: + data[f"{mgroup_name}_缺陷_{item['defect__name']}"] = item["total"] + data[f"{mgroup_name}_缺陷_{item['defect__name']}-比例"] = round((item["total"] / data[f"{mgroup_name}-count_real"])*100, 2) + + data[f"{mgroup_name}_日期"] = list(set(data[f"{mgroup_name}_日期"])) + data[f"{mgroup_name}_日期"] = ";".join([item.strftime("%Y-%m-%d") for item in data[f"{mgroup_name}_日期"]]) + data[f"{mgroup_name}_操作人"] = list(set(data[f"{mgroup_name}_操作人"])) + data[f"{mgroup_name}_操作人"] = ";".join([item.name for item in data[f"{mgroup_name}_操作人"]]) + + mlogb2_qs = Mlogb.objects.filter(mlog__submit_time__isnull=False, material_out__isnull=False, mlog__mgroup__name="外观检验", mlog__is_fix=True, batch=batch) + if mlogb2_qs.exists(): + data["外观检验_返修_日期"] = [] + data["外观检验_返修_操作人"] = [] + data["外观检验_返修_count_real"] = 0 + data["外观检验_返修_count_ok"] = 0 + data["外观检验_返修_count_ok_full"] = 0 + for item in mlogb2_qs: + if item.mlog.handle_user: + data["外观检验_返修_操作人"].append(item.mlog.handle_user) + if item.mlog.handle_date: + data["外观检验_返修_日期"].append(item.mlog.handle_date) + data["外观检验_返修_count_real"] += item.count_real + data["外观检验_返修_count_ok"] += item.count_ok + data["外观检验_返修_count_ok_full"] += item.count_ok_full + + data["外观检验_返修_日期"] = list(set(data["外观检验_返修_日期"])) + data["外观检验_返修_日期"] = ";".join([item.strftime("%Y-%m-%d") for item in data["外观检验_返修_日期"]]) + data["外观检验_返修_操作人"] = list(set(data["外观检验_返修_操作人"])) + data["外观检验_返修_操作人"] = ";".join([item.name for item in data["外观检验_返修_操作人"]]) + + mlogbd2_qs = MlogbDefect.objects.filter(mlogb__in=mlogb2_qs, count__gt=0).values("defect__name").annotate(total=Sum("count")) + + for item in mlogbd2_qs: + data[f"外观检验_返修_缺陷_{item['defect__name']}"] = item["total"] + data[f"外观检验_返修_缺陷_{item['defect__name']}-比例"] = round((item["total"] / data["外观检验_返修-count_real"])*100, 2) + + if "外观检验_count_ok" in data: + data["外观检验_总合格数"] = data["外观检验_count_ok"] + data["外观检验_返修_count_ok"] if "外观检验_返修_count_ok" in data else 0 + try: + data["外观检验_总合格率"] = round((data["外观检验_总合格数"] / data["外观检验_count_real"])*100, 2) + except decimal.InvalidOperation: + data["外观检验_总合格率"] = 0 + + try: + data["外观检验_直通合格率"] = round((data["外观检验_总合格率"]* data["尺寸检验_合格率"])/100, 2) + except decimal.InvalidOperation: + data["外观检验_直通合格率"] = 0 + + return data, {} + +if __name__ == '__main__': + pass \ No newline at end of file diff --git a/apps/wpm/services_2.py b/apps/wpm/services_2.py index 1f0787ff..6e7fedf9 100644 --- a/apps/wpm/services_2.py +++ b/apps/wpm/services_2.py @@ -12,33 +12,31 @@ import decimal import logging myLogger = logging.getLogger('log') -def get_alldata_with_batch_and_store(batch: str, need_update_time=True): +def get_alldata_with_batch_and_store(batch: str): """ 获取某个批次的整体生产数据并保存 """ - need_update = False + data = None + action = "get" BASE_PROJECT_CODE = getattr(settings, "BASE_PROJECT_CODE", None) if BASE_PROJECT_CODE == "gzerp": - need_update = True - last_time, data = get_alldata_with_batch(batch) + action = "get_or_create" + data, extra = get_alldata_with_batch(batch) elif BASE_PROJECT_CODE == "gxerp": - need_update = True - last_time, data = get_alldata_with_batch_gx(batch) - - if need_update and last_time and data: - bobj, _ = BatchSt.objects.get_or_create(batch=batch, defaults={ - "last_time": last_time - }) - if need_update_time: - bobj.last_time = last_time + from apps.wpm.scripts.batch_gxerp import main + data, extra = main(batch) + + if data: + if action == "get_or_create": + bobj, _ = BatchSt.objects.get_or_create(batch=batch, version=1) + elif action == "get": + bobj = BatchSt.objects.get(batch=batch, version=1) bobj.data = json.loads(json.dumps(data, cls=MyJSONEncoder)) + for k, v in extra.items(): + if hasattr(bobj, k): + setattr(bobj, k, v) bobj.save() -def get_alldata_with_batch_gx(batch: str): - """ - 光芯获取batch的统计数据 - """ - return None, None def get_alldata_with_batch(batch: str): """ @@ -54,13 +52,19 @@ def get_alldata_with_batch(batch: str): mlog_count_fields = Mlog.count_fields() + first_time = None + material_start = None if mlogs_blcx_qs.exists(): data["产品规格"] = [] data["棒料成型_出料人"] = [] data["棒料成型_切料人"] = [] data["棒料成型_备注"] = "" for item in mlogs_blcx_qs: - last_time = item.update_time if item.update_time > last_time else last_time + utime = item.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material_out data["产品规格"].append(item.material_out) # 对象 if item.handle_user: data["棒料成型_出料人"].append(item.handle_user) # 对象 @@ -86,7 +90,7 @@ def get_alldata_with_batch(batch: str): except ZeroDivisionError: data["棒料成型_合格率"] = 0 except decimal.InvalidOperation: - myLogger.error(f"棒料成型_合格率计算错误decimal.InvalidOperation-{data}") + # myLogger.error(f"棒料成型_合格率计算错误decimal.InvalidOperation-{data}") data["棒料成型_合格率"] = 0 # 管料成型数据 @@ -96,7 +100,11 @@ def get_alldata_with_batch(batch: str): data["产品规格"] = [] data["管料成型_备注"] = "" for item in mlogs_glcx_qs: - last_time = item.update_time if item.update_time > last_time else last_time + utime = item.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material_out data["产品规格"].append(item.material_out) # 对象 if item.note: data["管料成型_备注"] = ";".join([data["管料成型_备注"], item.note]) @@ -119,7 +127,11 @@ def get_alldata_with_batch(batch: str): data["七车间入库_仓库执行人"] = [] data["七车间入库_检验备注"] = "" for item in mioitem_qs: - last_time = item.update_time if item.update_time > last_time else last_time + utime = item.mio.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material data["七车间入库_日期"].append(item.mio.inout_date) if item.test_note: data["七车间入库_检验备注"] = ";".join([data["七车间入库_检验备注"], item.test_note]) @@ -153,7 +165,11 @@ def get_alldata_with_batch(batch: str): data["十车间入库_日期"] = [] data["十车间入库_检验备注"] = "" for item in mioitem10_qs: - last_time = item.update_time if item.update_time > last_time else last_time + utime = item.mio.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material if item.test_note: data["十车间入库_检验备注"] = ";".join([data["十车间入库_检验备注"], item.test_note]) if item.mio.do_user: @@ -188,7 +204,15 @@ def get_alldata_with_batch(batch: str): data["产品规格"] = [] for item in mlogs_glth_qs: data["产品规格"].append(item.material_out) - last_time = item.update_time if item.update_time > last_time else last_time + utime = item.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if first_time is None: + first_time = item.update_time + else: + first_time = item.update_time if item.update_time < first_time else first_time + if material_start is None: + material_start = item.material_out if item.note: data["管料退火_备注"] = ";".join([data["管料退火_备注"], item.note]) if item.handle_date: @@ -220,7 +244,11 @@ def get_alldata_with_batch(batch: str): data["产品规格"] = [] for item in mioitem6_qs: data["产品规格"].append(item.material) - last_time = item.update_time if item.update_time > last_time else last_time + utime = item.mio.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material data["六车间领料_日期"].append(item.mio.inout_date) if item.mio.do_user: data["六车间领料_仓库执行人"].append(item.mio.do_user) @@ -252,11 +280,15 @@ def get_alldata_with_batch(batch: str): mgroups = Mgroup.objects.filter(name=mgroup_name) mlogs_qs = Mlog.objects.filter(submit_time__isnull=False, mgroup__in=mgroups, batch=batch) if mlogs_qs.exists(): - last_time = item.update_time if item.update_time > last_time else last_time data[f'六车间_{mgroup_name}_日期'] = [] data[f'六车间_{mgroup_name}_操作人'] = [] data[f'六车间_{mgroup_name}_备注'] = "" for item in mlogs_qs: + utime = item.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material_out if item.note: data[f'六车间_{mgroup_name}_备注'] = ";".join([data[f'六车间_{mgroup_name}_备注'], item.note]) if item.handle_date: @@ -276,7 +308,7 @@ def get_alldata_with_batch(batch: str): try: data[f'六车间_{mgroup_name}_合格率'] = round(data[f'六车间_{mgroup_name}_count_ok'] * 100/ data[f'六车间_{mgroup_name}_count_real'], 1) except decimal.InvalidOperation: - myLogger.error(f"六车间_{mgroup_name}_合格率decimal.InvalidOperation-{data}") + # myLogger.error(f"六车间_{mgroup_name}_合格率decimal.InvalidOperation-{data}") data[f'六车间_{mgroup_name}_合格率'] = 0 ftestwork_count_fields = FtestWork.count_fields() @@ -286,7 +318,11 @@ def get_alldata_with_batch(batch: str): data["六车间中检_日期"] = [] data['六车间中检_检验人'] = [] for item in ftestwork_qs: - last_time = item.update_time if item.update_time > last_time else last_time + utime = item.update_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material if item.test_date: data["六车间中检_日期"].append(item.test_date) if item.test_user: @@ -318,6 +354,11 @@ def get_alldata_with_batch(batch: str): data["六车间生产入库_检验日期"] = [] data["六车间生产入库_检验人"] = [] for item in mioitem6_qs2: + utime = item.mio.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material data["六车间生产入库_日期"].append(item.mio.inout_date) if item.test_date: data["六车间生产入库_检验日期"].append(item.test_date) @@ -334,7 +375,7 @@ def get_alldata_with_batch(batch: str): try: data['六车间生产入库_合格率'] = round((data['六车间生产入库_count'] - data['六车间生产入库_count_notok']) * 100/ data['六车间生产入库_count'], 1) except decimal.InvalidOperation: - myLogger.error("六车间生产入库_合格率decimal.InvalidOperation-{data}") + # myLogger.error("六车间生产入库_合格率decimal.InvalidOperation-{data}") data['六车间生产入库_合格率'] = 0 # 成品检验数据 @@ -343,7 +384,11 @@ def get_alldata_with_batch(batch: str): data["成品检验_日期"] = [] data['成品检验_检验人'] = [] for item in ftestwork_qs: - last_time = item.update_time if item.update_time > last_time else last_time + utime = item.update_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material if item.test_date: data["成品检验_日期"].append(item.test_date) if item.test_user: @@ -378,7 +423,11 @@ def get_alldata_with_batch(batch: str): data['销售发货_仓库执行人'] = [] data['销售发货_count'] = 0 for item in mioitem_qs: - last_time = item.mio.update_time if item.mio.update_time > last_time else last_time + utime = item.mio.submit_time + last_time = utime if utime > last_time else last_time + first_time = utime if first_time is None else (utime if utime < first_time else first_time) + if material_start is None: + material_start = item.material if item.mio.inout_date: data["销售发货_日期"].append(item.mio.inout_date) if item.mio.do_user: @@ -390,5 +439,5 @@ def get_alldata_with_batch(batch: str): data["六车间_批次发货合格率"] = round(data["销售发货_count"] * 100/ data["六车间领料_count"], 1) data['销售发货_仓库执行人'] = ";".join([item.name for item in data['销售发货_仓库执行人']]) - return last_time, data + return data, {"material_start": material_start, "last_time": last_time, "first_time": first_time} \ No newline at end of file diff --git a/apps/wpm/views.py b/apps/wpm/views.py index 67c49ed1..56db113b 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -602,8 +602,8 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust m_dict['batch'] = generate_new_batch(mlogbin.batch, mlog) if mtype == Process.PRO_NORMAL: # 正常 支持批到批, 个到个 - d_count_real = mlogbin.count_use - d_count_ok = mlogbin.count_use + d_count_real = mlogbin.count_use - mlogbin.count_pn_jgqbl + d_count_ok = d_count_real mlogbout, _ = Mlogb.objects.get_or_create(mlogb_from=mlogbin, defaults= update_dict(m_dict, {"count_real": d_count_real, "count_ok": d_count_ok})) mlogbout.count_json_from = mlogbin.count_json_from @@ -627,7 +627,7 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust mlogbout.number_from = mlogbwin.number mlogbout.save() elif material_in.tracking == Material.MA_TRACKING_SINGLE and material_out.tracking == Material.MA_TRACKING_SINGLE: - d_count_real = mlogbin.count_use * div_number + d_count_real = (mlogbin.count_use-mlogbin.count_pn_jgqbl) * div_number d_count_ok = d_count_real mlogbout, _ = Mlogb.objects.get_or_create(mlogb_from=mlogbin, defaults=update_dict(m_dict, {"count_real": d_count_real, "count_ok": d_count_ok})) @@ -639,13 +639,13 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust for i in range(div_number): Mlogbw.objects.get_or_create(mlogb=mlogbout, number=f'{wpr_.number}-{i+1}', defaults={"mlogbw_from": mlogbwin}) elif material_in.tracking == Material.MA_TRACKING_BATCH and material_out.tracking == Material.MA_TRACKING_BATCH: - d_count_real = mlogbin.count_use * div_number + d_count_real = (mlogbin.count_use-mlogbin.count_pn_jgqbl) * div_number d_count_ok = d_count_real mlogbout, _ = Mlogb.objects.get_or_create(mlogb_from=mlogbin, defaults=update_dict(m_dict,{"count_real": d_count_real, "count_ok": d_count_ok})) mlogbout.count_json_from = mlogbin.count_json_from mlogbout.save(update_fields=["count_json_from"]) elif mtype == Process.PRO_MERGE: # 支持批到批,批到个 - xcount = math.floor( mlogbin.count_use / route.div_number) + xcount = math.floor( (mlogbin.count_use-mlogbin.count_pn_jgqbl) / route.div_number) d_count_real = xcount d_count_ok = xcount mlogbout, _ = Mlogb.objects.get_or_create(mlogb_from=mlogbin, defaults=update_dict(m_dict, {"count_real": d_count_real, "count_ok": d_count_ok})) @@ -661,8 +661,8 @@ class MlogbInViewSet(CreateModelMixin, UpdateModelMixin, DestroyModelMixin, Cust for i in range(d_count_real): Mlogbw.objects.get_or_create(number=f'{number}-{i+1}', mlogb=mlogbout) elif is_fix:# 支持批到批,个到个 - d_count_real = mlogbin.count_use - d_count_ok = mlogbin.count_use + d_count_real = mlogbin.count_use-mlogbin.count_pn_jgqbl + d_count_ok = d_count_real Mlogb.objects.get_or_create(mlogb_from=mlogbin, defaults=update_dict(m_dict,{"count_real": d_count_real, "count_ok": d_count_ok})) if material_in.tracking == Material.MA_TRACKING_SINGLE and material_out.tracking == Material.MA_TRACKING_SINGLE: for mlogbwin in Mlogbw.objects.filter(mlogb=mlogbin).order_by("number"): diff --git a/changelog.md b/changelog.md index 0daaedaf..185badce 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,21 @@ +## 2.6.2025051208 +- feat: 新增功能 + - 光芯质检表格 [caoqianming] + - base 短信发送功能启动抛出异常 [caoqianming] + - batchst字段同步数据库 [caoqianming] +## 2.6.2025050816 +- feat: 新增功能 + - batchst添加字段并更新光子的统计 [caoqianming] + - 由输入转输出需考虑到加工前不良的影响 [caoqianming] + - 初步添加光芯的批次分析函数 [caoqianming] + - myjsonfield优化 [caoqianming] + - mioitem添加排序字段 [caoqianming] + - 标签物料根据模板打印功能 [caoqianming] + - ichat 修改接口去掉langchain [zty] +- fix: 问题修复 + - gen_commands bug [caoqianming] + - labeltemplate filter bug [caoqianming] + - 标签模板筛选bug [caoqianming] ## 2.6.2025043014 - feat: 新增功能 - 生产入库和领料支持b类合格品 [caoqianming] diff --git a/server/settings.py b/server/settings.py index 40d9f3dd..ceb15bd1 100755 --- a/server/settings.py +++ b/server/settings.py @@ -35,7 +35,7 @@ sys.path.insert(0, os.path.join(BASE_DIR, 'apps')) ALLOWED_HOSTS = ['*'] SYS_NAME = '星途工厂综合管理系统' -SYS_VERSION = '2.6.2025043014' +SYS_VERSION = '2.6.2025051208' X_FRAME_OPTIONS = 'SAMEORIGIN' # Application definition