From ddb517d1f8cc99a28e50820aa95769e8c62c46be Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 18 Dec 2024 14:53:21 +0800 Subject: [PATCH 01/13] =?UTF-8?q?feat:=20material=E5=A2=9E=E5=8A=A0trackin?= =?UTF-8?q?g=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mtm/migrations/0048_auto_20241218_1431.py | 23 +++++++++++++++++++ apps/mtm/models.py | 8 ++++++- apps/mtm/serializers.py | 5 +++- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 apps/mtm/migrations/0048_auto_20241218_1431.py diff --git a/apps/mtm/migrations/0048_auto_20241218_1431.py b/apps/mtm/migrations/0048_auto_20241218_1431.py new file mode 100644 index 00000000..e9e39946 --- /dev/null +++ b/apps/mtm/migrations/0048_auto_20241218_1431.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.12 on 2024-12-18 06:31 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0047_route_div_number'), + ] + + operations = [ + migrations.AddField( + model_name='material', + name='tracking', + field=models.PositiveSmallIntegerField(choices=[(10, '批次'), (20, '单件')], default=10, verbose_name='追踪方式'), + ), + migrations.AlterField( + model_name='material', + name='sort', + field=models.FloatField(default=1, verbose_name='排序'), + ), + ] diff --git a/apps/mtm/models.py b/apps/mtm/models.py index 193888c3..31756949 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -55,6 +55,9 @@ class Material(CommonAModel): (MA_TYPE_OFFICE, '办公用品') ) + MA_TRACKING_BATCH = 10 + MA_TRACKING_SINGLE = 20 + name = models.CharField('名称', max_length=50) cate = models.CharField('大类', max_length=20, default='', blank=True) number = models.CharField('编号', max_length=100, null=True, blank=True) @@ -66,8 +69,11 @@ class Material(CommonAModel): type = models.PositiveSmallIntegerField( '物料类型', choices=type_choices, default=1, help_text=str(type_choices)) testitems = models.JSONField('检测项目', default=list, blank=True) - sort = models.PositiveSmallIntegerField('排序', default=1) + sort = models.FloatField('排序', default=1) unit = models.CharField('基准计量单位', default='个', max_length=10) + tracking = models.PositiveSmallIntegerField("追踪方式", default=10, + choices=((MA_TRACKING_BATCH, '批次'), + (MA_TRACKING_SINGLE, '单件'))) count = models.DecimalField('总库存', max_digits=14, decimal_places=3, default=0) count_mb = models.DecimalField('仓库库存', max_digits=14, decimal_places=3, default=0) count_wm = models.DecimalField('车间库存', max_digits=14, decimal_places=3, default=0) diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index cf41fa79..61cd2495 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -183,7 +183,7 @@ class RouteSerializer(CustomModelSerializer): """ material = instance.material process = instance.process - material_out = Material.objects.get_queryset(all=True).filter(type=Material.MA_TYPE_HALFGOOD, parent=material, process=process).first() + material_out: Material = Material.objects.get_queryset(all=True).filter(type=Material.MA_TYPE_HALFGOOD, parent=material, process=process).first() if material_out: material_out.is_deleted = False if material_out.parent == material: @@ -191,6 +191,7 @@ class RouteSerializer(CustomModelSerializer): material_out.model = material.model material_out.specification = material.specification material_out.cate = material.cate + material_out.tracking = material.tracking material_out.save() instance.material_out = material_out instance.save() @@ -201,6 +202,7 @@ class RouteSerializer(CustomModelSerializer): if material_out.parent is None: material_out.parent = material material_out.cate = material.cate + material_out.tracking = material.tracking material_out.save() instance.material_out = material_out instance.save() @@ -212,6 +214,7 @@ class RouteSerializer(CustomModelSerializer): 'model': material.model, 'type': Material.MA_TYPE_HALFGOOD, 'cate': material.cate, + 'tracking': material.tracking, 'create_by': self.request.user, 'update_by': self.request.user, }) From 468f5ffdbfa60941d2f7fd9cdb924862d332fb39 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 19 Dec 2024 10:11:27 +0800 Subject: [PATCH 02/13] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E6=A8=A1=E6=9D=BF=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/migrations/0029_auto_20241219_1006.py | 87 +++++++++++++++++++ apps/qm/models.py | 32 +++++++ apps/qm/serializers.py | 29 ++++++- apps/qm/urls.py | 5 +- apps/qm/views.py | 42 ++++++++- 5 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 apps/qm/migrations/0029_auto_20241219_1006.py diff --git a/apps/qm/migrations/0029_auto_20241219_1006.py b/apps/qm/migrations/0029_auto_20241219_1006.py new file mode 100644 index 00000000..2dddeeb1 --- /dev/null +++ b/apps/qm/migrations/0029_auto_20241219_1006.py @@ -0,0 +1,87 @@ +# Generated by Django 3.2.12 on 2024-12-19 02:06 + +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', '0048_auto_20241218_1431'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('qm', '0028_defect'), + ] + + operations = [ + migrations.CreateModel( + name='Qct', + 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='删除标记')), + ('name', models.CharField(max_length=50, verbose_name='名称')), + ('number', models.CharField(max_length=20, verbose_name='编号')), + ('tags', models.JSONField(blank=True, default=list, verbose_name='检测类型')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qct_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='QctMat', + 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='删除标记')), + ('tracing', models.CharField(choices=[('test', '检测项'), ('defect', '缺陷项')], default='test', help_text="(('test', '检测项'), ('defect', '缺陷项'))", max_length=20, verbose_name='追溯层级')), + ('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='物料')), + ('qc', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='QctItem', + 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, null=True, verbose_name='备注')), + ('rule_expression', models.TextField(blank=True, null=True, verbose_name='判定表达式')), + ('sort', models.FloatField(default=1, verbose_name='排序')), + ('defect', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.defect', verbose_name='缺陷项')), + ('qc', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')), + ('testitem', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testitem', verbose_name='检测项')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='qct', + name='defects', + field=models.ManyToManyField(blank=True, through='qm.QctItem', to='qm.Defect', verbose_name='缺陷项'), + ), + migrations.AddField( + model_name='qct', + name='materials', + field=models.ManyToManyField(blank=True, through='qm.QctMat', to='mtm.Material', verbose_name='物料'), + ), + migrations.AddField( + model_name='qct', + name='testitems', + field=models.ManyToManyField(blank=True, through='qm.QctItem', to='qm.TestItem', verbose_name='检测项'), + ), + migrations.AddField( + model_name='qct', + name='update_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='qct_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index 931f183c..2611f7a5 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -21,6 +21,7 @@ class Defect(CommonAModel): def __str__(self): return self.name + class NotOkOption(models.TextChoices): # 不合格项 zw = "zw", _("炸纹") @@ -124,6 +125,37 @@ class TestItem(CommonAModel): ordering = ['sort', '-create_time'] +QC_T = 'test' +QC_D = 'defect' + +QC_TRACE_CHOICES = ( + (QC_T, '检测项'), + (QC_D, '缺陷项') +) + +class Qct(CommonAModel): + # 检测模板 + name = models.CharField(max_length=50, verbose_name="名称") + number = models.CharField(max_length=20, verbose_name="编号") + tags = models.JSONField('检测类型', default=list, blank=True) + testitems = models.ManyToManyField(TestItem, verbose_name="检测项", blank=True, through='qm.qctItem') + defects = models.ManyToManyField(Defect, verbose_name="缺陷项", blank=True, through='qm.qctItem') + materials = models.ManyToManyField(Material, verbose_name="物料", blank=True, through='qm.qctmat') + +class QctItem(BaseModel): + qc = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) + testitem = models.ForeignKey(TestItem, verbose_name="检测项", on_delete=models.CASCADE, null=True, blank=True) + note = models.TextField('备注', null=True, blank=True) + rule_expression = models.TextField('判定表达式', null=True, blank=True) + defect = models.ForeignKey(Defect, verbose_name="缺陷项", on_delete=models.CASCADE, null=True, blank=True) + sort = models.FloatField('排序', default=1) + +class QctMat(BaseModel): + qc = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) + material = models.ForeignKey(Material, verbose_name="物料", on_delete=models.CASCADE) + tracing = models.CharField('追溯层级', default=QC_T, choices=QC_TRACE_CHOICES, max_length=20, help_text=str(QC_TRACE_CHOICES)) + + class QuaStat(CommonBDModel): """ 质量数据表 diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index 66f95b38..1a8892e9 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -1,4 +1,5 @@ -from apps.qm.models import QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest, NotOkOption, Defect +from apps.qm.models import (QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest, + NotOkOption, Defect, Qct, QctItem, QctMat) from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE from apps.utils.serializers import CustomModelSerializer from rest_framework import serializers @@ -29,6 +30,32 @@ class TestItemSerializer(CustomModelSerializer): fields = '__all__' read_only_fields = EXCLUDE_FIELDS +class QctSerializer(CustomModelSerializer): + class Meta: + model = Qct + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + +class QctItemSerializer(CustomModelSerializer): + defect_name = serializers.StringRelatedField(source='defect', read_only=True) + testitem_name = serializers.CharField(source='testitem.name', read_only=True) + class Meta: + model = Qct + fields = '__all__' + +class QctMatSerializer(CustomModelSerializer): + material_name = serializers.StringRelatedField(source='material', read_only=True) + class Meta: + model = QctMat + fields = '__all__' + +class QctDetailSerializer(CustomModelSerializer): + testitems_ = QctItemSerializer(source="testitems", many=True, read_only=True) + defects_ = DefectSerializer(source="defects", many=True, read_only=True) + class Meta: + model = Qct + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS class QuaStatSerializer(CustomModelSerializer): sflog = serializers.PrimaryKeyRelatedField( diff --git a/apps/qm/urls.py b/apps/qm/urls.py index a0f5c777..843cb006 100644 --- a/apps/qm/urls.py +++ b/apps/qm/urls.py @@ -3,7 +3,7 @@ from rest_framework.routers import DefaultRouter from apps.qm.views import (QuaStatViewSet, TestItemViewSet, FtestWorkViewSet, FtestViewSet, PtestViewSet, - NotOkOptionView, DefectViewSet) + NotOkOptionView, DefectViewSet, QctViewSet, QctItemViewSet, QctMatViewSet) API_BASE_URL = 'api/qm/' HTML_BASE_URL = 'qm/' @@ -15,6 +15,9 @@ router.register('ftest', FtestViewSet, basename='ftest') router.register('ftestwork', FtestWorkViewSet, basename='ftestwork') router.register('ptest', PtestViewSet, basename='ptest') router.register("defect", DefectViewSet, basename="defect") +router.register('qct', QctViewSet, basename='qct') +router.register('qctitem', QctItemViewSet, basename='qctitem') +router.register('qctmat', QctMatViewSet, basename='qctmat') urlpatterns = [ path(API_BASE_URL, include(router.urls)), path(API_BASE_URL + 'notok_option/', NotOkOptionView.as_view()), diff --git a/apps/qm/views.py b/apps/qm/views.py index fa803a8c..938b9f31 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -5,7 +5,8 @@ from rest_framework.views import APIView from rest_framework.serializers import Serializer from apps.qm.models import QuaStat, TestItem, Ftest, Ptest, FtestWork from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer, FtestSerializer, PtestSerializer, \ - FtestWorkCreateUpdateSerializer, FtestWorkSerializer, DefectSerializer + FtestWorkCreateUpdateSerializer, FtestWorkSerializer, DefectSerializer, QctSerializer, QctItemSerializer, QctMatSerializer, \ + QctDetailSerializer from apps.qm.tasks import cal_quastat_sflog from rest_framework.response import Response from apps.utils.mixins import BulkUpdateModelMixin @@ -15,7 +16,7 @@ from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.wpm.models import SfLog from apps.qm.filters import QuaStatFilter, TestItemFilter, FtestWorkFilter from django.db import transaction -from apps.qm.models import NotOkOption, Defect +from apps.qm.models import NotOkOption, Defect, Qct, QctItem, QctMat from apps.qm.services import ftestwork_submit from apps.utils.thread import MyThread from apps.wpm.services_2 import get_alldata_with_batch_and_store @@ -24,7 +25,7 @@ from apps.wf.models import State class DefectViewSet(CustomModelViewSet): """ - list:缺陷项 + list: 缺陷项 缺陷项 """ @@ -33,6 +34,41 @@ class DefectViewSet(CustomModelViewSet): filterset_fields = ["cate", "okcate"] search_fields = ["name", "code"] +class QctViewSet(CustomModelViewSet): + """ + list: 检测模板 + + 检测模板 + """ + queryset = Qct.objects.all() + serializer_class = QctSerializer + retrieve_serializer_class = QctDetailSerializer + filterset_fields = ["tags", "testitems", "defects"] + search_fields = ["name", "number"] + +class QctItemViewSet(CustomModelViewSet): + """ + list: 检测模板项 + + 检测模板项 + """ + perms_map = {"get": "*", "post": "qct.update", "put": "qct.update", "delete": "qct.update"} + queryset = QctItem.objects.all() + serializer_class = QctItemSerializer + filterset_fields = ["qct", "testitem", "defect"] + ordering = ["qc", "sort"] + +class QctMatViewSet(CustomModelViewSet): + """ + list: 检测物料 + + 检测物料 + """ + perms_map = {"get": "*", "post": "qct.update", "put": "qct.update", "delete": "qct.update"} + queryset = QctMat.objects.all() + serializer_class = QctMatSerializer + filterset_fields = ["qct", "material"] + class NotOkOptionView(APIView): perms_map = {'get': '*'} From e7c08dc16cb201397d8a48643cf4bec0d3eb257e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 19 Dec 2024 10:12:24 +0800 Subject: [PATCH 03/13] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E6=A8=A1=E6=9D=BF=E5=8A=9F=E8=83=BDQctItemSerializer?= =?UTF-8?q?=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index 1a8892e9..34506f4f 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -40,7 +40,7 @@ class QctItemSerializer(CustomModelSerializer): defect_name = serializers.StringRelatedField(source='defect', read_only=True) testitem_name = serializers.CharField(source='testitem.name', read_only=True) class Meta: - model = Qct + model = QctItem fields = '__all__' class QctMatSerializer(CustomModelSerializer): From 1647b2f06e350669e7461e0255be7a70c7c00a06 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 19 Dec 2024 11:04:16 +0800 Subject: [PATCH 04/13] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E6=A3=80?= =?UTF-8?q?=E6=B5=8B=E6=A8=A1=E6=9D=BF=E5=8A=9F=E8=83=BD=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/filters.py | 9 ++++++++- ...o_20241219_1006.py => 0029_auto_20241219_1034.py} | 8 ++++---- apps/qm/models.py | 4 ++-- apps/qm/views.py | 12 +++++------- 4 files changed, 19 insertions(+), 14 deletions(-) rename apps/qm/migrations/{0029_auto_20241219_1006.py => 0029_auto_20241219_1034.py} (94%) diff --git a/apps/qm/filters.py b/apps/qm/filters.py index 162c793e..4aba5326 100644 --- a/apps/qm/filters.py +++ b/apps/qm/filters.py @@ -1,5 +1,6 @@ from django_filters import rest_framework as filters -from apps.qm.models import QuaStat, TestItem, FtestWork +from apps.qm.models import QuaStat, TestItem, FtestWork, Qct +from apps.utils.filters import MyJsonListFilter class QuaStatFilter(filters.FilterSet): @@ -14,6 +15,12 @@ class QuaStatFilter(filters.FilterSet): "sflog__end_time": ["day", "month", "year", "lt"], } +class QctFilter(filters.FilterSet): + tags = MyJsonListFilter(label="tags查询,分隔") + + class Meta: + model = Qct + fields = ["testitems", "defects"] class TestItemFilter(filters.FilterSet): tags__contains = filters.CharFilter(field_name='tags', lookup_expr='contains') diff --git a/apps/qm/migrations/0029_auto_20241219_1006.py b/apps/qm/migrations/0029_auto_20241219_1034.py similarity index 94% rename from apps/qm/migrations/0029_auto_20241219_1006.py rename to apps/qm/migrations/0029_auto_20241219_1034.py index 2dddeeb1..2f2b08f9 100644 --- a/apps/qm/migrations/0029_auto_20241219_1006.py +++ b/apps/qm/migrations/0029_auto_20241219_1034.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.12 on 2024-12-19 02:06 +# Generated by Django 3.2.12 on 2024-12-19 02:34 from django.conf import settings from django.db import migrations, models @@ -9,8 +9,8 @@ import django.utils.timezone class Migration(migrations.Migration): dependencies = [ - ('mtm', '0048_auto_20241218_1431'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('mtm', '0048_auto_20241218_1431'), ('qm', '0028_defect'), ] @@ -40,7 +40,7 @@ class Migration(migrations.Migration): ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), ('tracing', models.CharField(choices=[('test', '检测项'), ('defect', '缺陷项')], default='test', help_text="(('test', '检测项'), ('defect', '缺陷项'))", max_length=20, verbose_name='追溯层级')), ('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='物料')), - ('qc', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')), + ('qct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')), ], options={ 'abstract': False, @@ -57,7 +57,7 @@ class Migration(migrations.Migration): ('rule_expression', models.TextField(blank=True, null=True, verbose_name='判定表达式')), ('sort', models.FloatField(default=1, verbose_name='排序')), ('defect', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.defect', verbose_name='缺陷项')), - ('qc', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')), + ('qct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')), ('testitem', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testitem', verbose_name='检测项')), ], options={ diff --git a/apps/qm/models.py b/apps/qm/models.py index 2611f7a5..5b34a674 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -143,7 +143,7 @@ class Qct(CommonAModel): materials = models.ManyToManyField(Material, verbose_name="物料", blank=True, through='qm.qctmat') class QctItem(BaseModel): - qc = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) + qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) testitem = models.ForeignKey(TestItem, verbose_name="检测项", on_delete=models.CASCADE, null=True, blank=True) note = models.TextField('备注', null=True, blank=True) rule_expression = models.TextField('判定表达式', null=True, blank=True) @@ -151,7 +151,7 @@ class QctItem(BaseModel): sort = models.FloatField('排序', default=1) class QctMat(BaseModel): - qc = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) + qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) material = models.ForeignKey(Material, verbose_name="物料", on_delete=models.CASCADE) tracing = models.CharField('追溯层级', default=QC_T, choices=QC_TRACE_CHOICES, max_length=20, help_text=str(QC_TRACE_CHOICES)) diff --git a/apps/qm/views.py b/apps/qm/views.py index 938b9f31..d9e03922 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -14,7 +14,7 @@ import datetime from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.wpm.models import SfLog -from apps.qm.filters import QuaStatFilter, TestItemFilter, FtestWorkFilter +from apps.qm.filters import QuaStatFilter, TestItemFilter, FtestWorkFilter, QctFilter from django.db import transaction from apps.qm.models import NotOkOption, Defect, Qct, QctItem, QctMat from apps.qm.services import ftestwork_submit @@ -43,12 +43,11 @@ class QctViewSet(CustomModelViewSet): queryset = Qct.objects.all() serializer_class = QctSerializer retrieve_serializer_class = QctDetailSerializer - filterset_fields = ["tags", "testitems", "defects"] + filterset_class = QctFilter search_fields = ["name", "number"] class QctItemViewSet(CustomModelViewSet): - """ - list: 检测模板项 + """检测模板项 检测模板项 """ @@ -56,11 +55,10 @@ class QctItemViewSet(CustomModelViewSet): queryset = QctItem.objects.all() serializer_class = QctItemSerializer filterset_fields = ["qct", "testitem", "defect"] - ordering = ["qc", "sort"] + ordering = ["qct", "sort"] class QctMatViewSet(CustomModelViewSet): - """ - list: 检测物料 + """检测物料 检测物料 """ From 796cdbc6157638e069d60f89557034d63921ccd1 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 19 Dec 2024 11:07:08 +0800 Subject: [PATCH 05/13] =?UTF-8?q?feat:=20base=20listmixin=E6=8F=8F?= =?UTF-8?q?=E8=BF=B0=E5=8E=BB=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/utils/mixins.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/apps/utils/mixins.py b/apps/utils/mixins.py index 67931b84..c7595057 100755 --- a/apps/utils/mixins.py +++ b/apps/utils/mixins.py @@ -185,11 +185,7 @@ class CustomListModelMixin(ListModelMixin): type=openapi.TYPE_STRING, required=False), ]) def list(self, request, *args, **kwargs): - """ - 获取列表 - 获取列表 - """ queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) From b289c7813ee2b6842068326aa2f3a52cbf88e8d3 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 19 Dec 2024 15:10:12 +0800 Subject: [PATCH 06/13] =?UTF-8?q?feat:=20qct=20=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...219_1034.py => 0029_auto_20241219_1509.py} | 29 ++++++++++++++----- apps/qm/models.py | 13 ++++++--- apps/qm/serializers.py | 16 ++++++---- apps/qm/urls.py | 5 ++-- apps/qm/views.py | 27 ++++++++++++----- 5 files changed, 64 insertions(+), 26 deletions(-) rename apps/qm/migrations/{0029_auto_20241219_1034.py => 0029_auto_20241219_1509.py} (78%) diff --git a/apps/qm/migrations/0029_auto_20241219_1034.py b/apps/qm/migrations/0029_auto_20241219_1509.py similarity index 78% rename from apps/qm/migrations/0029_auto_20241219_1034.py rename to apps/qm/migrations/0029_auto_20241219_1509.py index 2f2b08f9..6162dcba 100644 --- a/apps/qm/migrations/0029_auto_20241219_1034.py +++ b/apps/qm/migrations/0029_auto_20241219_1509.py @@ -1,4 +1,4 @@ -# Generated by Django 3.2.12 on 2024-12-19 02:34 +# Generated by Django 3.2.12 on 2024-12-19 07:09 from django.conf import settings from django.db import migrations, models @@ -31,6 +31,22 @@ class Migration(migrations.Migration): 'abstract': False, }, ), + migrations.CreateModel( + name='QctTestItem', + 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, null=True, verbose_name='备注')), + ('sort', models.FloatField(default=1, verbose_name='排序')), + ('qct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')), + ('testitem', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testitem', verbose_name='检测项')), + ], + options={ + 'abstract': False, + }, + ), migrations.CreateModel( name='QctMat', fields=[ @@ -47,18 +63,17 @@ class Migration(migrations.Migration): }, ), migrations.CreateModel( - name='QctItem', + name='QctDefect', 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, null=True, verbose_name='备注')), ('rule_expression', models.TextField(blank=True, null=True, verbose_name='判定表达式')), + ('note', models.TextField(blank=True, null=True, verbose_name='备注')), ('sort', models.FloatField(default=1, verbose_name='排序')), - ('defect', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.defect', verbose_name='缺陷项')), + ('defect', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.defect', verbose_name='缺陷项')), ('qct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')), - ('testitem', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testitem', verbose_name='检测项')), ], options={ 'abstract': False, @@ -67,7 +82,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='qct', name='defects', - field=models.ManyToManyField(blank=True, through='qm.QctItem', to='qm.Defect', verbose_name='缺陷项'), + field=models.ManyToManyField(blank=True, through='qm.QctDefect', to='qm.Defect', verbose_name='缺陷项'), ), migrations.AddField( model_name='qct', @@ -77,7 +92,7 @@ class Migration(migrations.Migration): migrations.AddField( model_name='qct', name='testitems', - field=models.ManyToManyField(blank=True, through='qm.QctItem', to='qm.TestItem', verbose_name='检测项'), + field=models.ManyToManyField(blank=True, through='qm.QctTestItem', to='qm.TestItem', verbose_name='检测项'), ), migrations.AddField( model_name='qct', diff --git a/apps/qm/models.py b/apps/qm/models.py index 5b34a674..c811cd1a 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -138,16 +138,21 @@ class Qct(CommonAModel): name = models.CharField(max_length=50, verbose_name="名称") number = models.CharField(max_length=20, verbose_name="编号") tags = models.JSONField('检测类型', default=list, blank=True) - testitems = models.ManyToManyField(TestItem, verbose_name="检测项", blank=True, through='qm.qctItem') - defects = models.ManyToManyField(Defect, verbose_name="缺陷项", blank=True, through='qm.qctItem') + testitems = models.ManyToManyField(TestItem, verbose_name="检测项", blank=True, through='qm.qcttestitem') + defects = models.ManyToManyField(Defect, verbose_name="缺陷项", blank=True, through='qm.qctdefect') materials = models.ManyToManyField(Material, verbose_name="物料", blank=True, through='qm.qctmat') -class QctItem(BaseModel): +class QctTestItem(BaseModel): qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) testitem = models.ForeignKey(TestItem, verbose_name="检测项", on_delete=models.CASCADE, null=True, blank=True) note = models.TextField('备注', null=True, blank=True) + sort = models.FloatField('排序', default=1) + +class QctDefect(BaseModel): + qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) + defect = models.ForeignKey(Defect, verbose_name="缺陷项", on_delete=models.CASCADE) rule_expression = models.TextField('判定表达式', null=True, blank=True) - defect = models.ForeignKey(Defect, verbose_name="缺陷项", on_delete=models.CASCADE, null=True, blank=True) + note = models.TextField('备注', null=True, blank=True) sort = models.FloatField('排序', default=1) class QctMat(BaseModel): diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index 34506f4f..2eb6ccee 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -1,5 +1,5 @@ from apps.qm.models import (QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest, - NotOkOption, Defect, Qct, QctItem, QctMat) + NotOkOption, Defect, Qct, QctTestItem, QctMat, QctDefect) from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE from apps.utils.serializers import CustomModelSerializer from rest_framework import serializers @@ -36,11 +36,16 @@ class QctSerializer(CustomModelSerializer): fields = '__all__' read_only_fields = EXCLUDE_FIELDS -class QctItemSerializer(CustomModelSerializer): - defect_name = serializers.StringRelatedField(source='defect', read_only=True) +class QctTestItemSerializer(CustomModelSerializer): testitem_name = serializers.CharField(source='testitem.name', read_only=True) class Meta: - model = QctItem + model = QctTestItem + fields = '__all__' + +class QctDefectSerializer(CustomModelSerializer): + defect_name = serializers.CharField(source='defect.name', read_only=True) + class Meta: + model = QctDefect fields = '__all__' class QctMatSerializer(CustomModelSerializer): @@ -50,7 +55,8 @@ class QctMatSerializer(CustomModelSerializer): fields = '__all__' class QctDetailSerializer(CustomModelSerializer): - testitems_ = QctItemSerializer(source="testitems", many=True, read_only=True) + testitems_ = QctTestItemSerializer(source="testitems", many=True, read_only=True) + defects_ = QctDefectSerializer(source="defects", many=True, read_only=True) defects_ = DefectSerializer(source="defects", many=True, read_only=True) class Meta: model = Qct diff --git a/apps/qm/urls.py b/apps/qm/urls.py index 843cb006..879f266e 100644 --- a/apps/qm/urls.py +++ b/apps/qm/urls.py @@ -3,7 +3,7 @@ from rest_framework.routers import DefaultRouter from apps.qm.views import (QuaStatViewSet, TestItemViewSet, FtestWorkViewSet, FtestViewSet, PtestViewSet, - NotOkOptionView, DefectViewSet, QctViewSet, QctItemViewSet, QctMatViewSet) + NotOkOptionView, DefectViewSet, QctViewSet, QctTestItemViewSet, QctDefectViewSet, QctMatViewSet) API_BASE_URL = 'api/qm/' HTML_BASE_URL = 'qm/' @@ -16,7 +16,8 @@ router.register('ftestwork', FtestWorkViewSet, basename='ftestwork') router.register('ptest', PtestViewSet, basename='ptest') router.register("defect", DefectViewSet, basename="defect") router.register('qct', QctViewSet, basename='qct') -router.register('qctitem', QctItemViewSet, basename='qctitem') +router.register('qcttestitem', QctTestItemViewSet, basename='qcttestitem') +router.register('qctdefect', QctDefectViewSet, basename="qctdefect") router.register('qctmat', QctMatViewSet, basename='qctmat') urlpatterns = [ path(API_BASE_URL, include(router.urls)), diff --git a/apps/qm/views.py b/apps/qm/views.py index d9e03922..522c6cb3 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -5,7 +5,7 @@ from rest_framework.views import APIView from rest_framework.serializers import Serializer from apps.qm.models import QuaStat, TestItem, Ftest, Ptest, FtestWork from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer, FtestSerializer, PtestSerializer, \ - FtestWorkCreateUpdateSerializer, FtestWorkSerializer, DefectSerializer, QctSerializer, QctItemSerializer, QctMatSerializer, \ + FtestWorkCreateUpdateSerializer, FtestWorkSerializer, DefectSerializer, QctSerializer, QctTestItemSerializer, QctDefectSerializer, QctMatSerializer, \ QctDetailSerializer from apps.qm.tasks import cal_quastat_sflog from rest_framework.response import Response @@ -16,7 +16,7 @@ from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.wpm.models import SfLog from apps.qm.filters import QuaStatFilter, TestItemFilter, FtestWorkFilter, QctFilter from django.db import transaction -from apps.qm.models import NotOkOption, Defect, Qct, QctItem, QctMat +from apps.qm.models import NotOkOption, Defect, Qct, QctTestItem, QctMat, QctDefect from apps.qm.services import ftestwork_submit from apps.utils.thread import MyThread from apps.wpm.services_2 import get_alldata_with_batch_and_store @@ -25,7 +25,7 @@ from apps.wf.models import State class DefectViewSet(CustomModelViewSet): """ - list: 缺陷项 + 缺陷项 缺陷项 """ @@ -36,7 +36,7 @@ class DefectViewSet(CustomModelViewSet): class QctViewSet(CustomModelViewSet): """ - list: 检测模板 + 检测模板 检测模板 """ @@ -46,15 +46,26 @@ class QctViewSet(CustomModelViewSet): filterset_class = QctFilter search_fields = ["name", "number"] -class QctItemViewSet(CustomModelViewSet): +class QctTestItemViewSet(CustomModelViewSet): """检测模板项 检测模板项 """ perms_map = {"get": "*", "post": "qct.update", "put": "qct.update", "delete": "qct.update"} - queryset = QctItem.objects.all() - serializer_class = QctItemSerializer - filterset_fields = ["qct", "testitem", "defect"] + queryset = QctTestItem.objects.all() + serializer_class = QctTestItemSerializer + filterset_fields = ["qct", "testitem"] + ordering = ["qct", "sort"] + +class QctDefectViewSet(CustomModelViewSet): + """检测缺陷项 + + 检测缺陷项 + """ + perms_map = {"get": "*", "post": "qct.update", "put": "qct.update", "delete": "qct.update"} + queryset = QctDefect.objects.all() + serializer_class = QctDefectSerializer + filterset_fields = ["qct", "defect"] ordering = ["qct", "sort"] class QctMatViewSet(CustomModelViewSet): From 7fa065ce88f43e1ca94ec13ff42dec9b61840b73 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 20 Dec 2024 14:42:03 +0800 Subject: [PATCH 07/13] =?UTF-8?q?feat:=20QctTestItem=20=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/migrations/0030_auto_20241220_1438.py | 29 +++++++++++++++++++ apps/qm/models.py | 3 ++ 2 files changed, 32 insertions(+) create mode 100644 apps/qm/migrations/0030_auto_20241220_1438.py diff --git a/apps/qm/migrations/0030_auto_20241220_1438.py b/apps/qm/migrations/0030_auto_20241220_1438.py new file mode 100644 index 00000000..1f6817cf --- /dev/null +++ b/apps/qm/migrations/0030_auto_20241220_1438.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.12 on 2024-12-20 06:38 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0029_auto_20241219_1509'), + ] + + operations = [ + migrations.AddField( + model_name='qcttestitem', + name='affect', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='qm.qcttestitem', verbose_name='影响项'), + ), + migrations.AddField( + model_name='qcttestitem', + name='formula', + field=models.TextField(blank=True, null=True, verbose_name='计算公式'), + ), + migrations.AddField( + model_name='qcttestitem', + name='readonly', + field=models.BooleanField(default=False, verbose_name='只读'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index c811cd1a..d2da5f64 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -145,6 +145,9 @@ class Qct(CommonAModel): class QctTestItem(BaseModel): qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) testitem = models.ForeignKey(TestItem, verbose_name="检测项", on_delete=models.CASCADE, null=True, blank=True) + readonly = models.BooleanField('只读', default=False) + formula = models.TextField('计算公式', null=True, blank=True) + affect = models.ForeignKey('self', verbose_name="影响项", on_delete=models.SET_NULL, null=True, blank=True) note = models.TextField('备注', null=True, blank=True) sort = models.FloatField('排序', default=1) From 4ab711cc71d441c62bdb61efede9dd8bd45c3831 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 20 Dec 2024 15:46:32 +0800 Subject: [PATCH 08/13] =?UTF-8?q?feat:=20formula=20=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E5=88=B0testitem?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ..._20241220_1438.py => 0030_auto_20241220_1544.py} | 13 ++++++------- apps/qm/models.py | 6 +++--- 2 files changed, 9 insertions(+), 10 deletions(-) rename apps/qm/migrations/{0030_auto_20241220_1438.py => 0030_auto_20241220_1544.py} (58%) diff --git a/apps/qm/migrations/0030_auto_20241220_1438.py b/apps/qm/migrations/0030_auto_20241220_1544.py similarity index 58% rename from apps/qm/migrations/0030_auto_20241220_1438.py rename to apps/qm/migrations/0030_auto_20241220_1544.py index 1f6817cf..5465467b 100644 --- a/apps/qm/migrations/0030_auto_20241220_1438.py +++ b/apps/qm/migrations/0030_auto_20241220_1544.py @@ -1,7 +1,6 @@ -# Generated by Django 3.2.12 on 2024-12-20 06:38 +# Generated by Django 3.2.12 on 2024-12-20 07:44 from django.db import migrations, models -import django.db.models.deletion class Migration(migrations.Migration): @@ -12,17 +11,17 @@ class Migration(migrations.Migration): operations = [ migrations.AddField( - model_name='qcttestitem', - name='affect', - field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='qm.qcttestitem', verbose_name='影响项'), + model_name='testitem', + name='affects', + field=models.JSONField(blank=True, default=list, verbose_name='影响项列表'), ), migrations.AddField( - model_name='qcttestitem', + model_name='testitem', name='formula', field=models.TextField(blank=True, null=True, verbose_name='计算公式'), ), migrations.AddField( - model_name='qcttestitem', + model_name='testitem', name='readonly', field=models.BooleanField(default=False, verbose_name='只读'), ), diff --git a/apps/qm/models.py b/apps/qm/models.py index d2da5f64..b140d06e 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -120,6 +120,9 @@ class TestItem(CommonAModel): mcate_tags = models.JSONField('物料系列标签', default=list, blank=True) sort = models.PositiveSmallIntegerField('排序', default=1) description = models.TextField('描述', default='') + readonly = models.BooleanField('只读', default=False) + formula = models.TextField('计算公式', null=True, blank=True) + affects = models.JSONField('影响项列表', default=list, blank=True) class Meta: ordering = ['sort', '-create_time'] @@ -145,9 +148,6 @@ class Qct(CommonAModel): class QctTestItem(BaseModel): qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) testitem = models.ForeignKey(TestItem, verbose_name="检测项", on_delete=models.CASCADE, null=True, blank=True) - readonly = models.BooleanField('只读', default=False) - formula = models.TextField('计算公式', null=True, blank=True) - affect = models.ForeignKey('self', verbose_name="影响项", on_delete=models.SET_NULL, null=True, blank=True) note = models.TextField('备注', null=True, blank=True) sort = models.FloatField('排序', default=1) From f4c84f0354d3915118e1977e5549dd6ddac65cad Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 20 Dec 2024 17:49:40 +0800 Subject: [PATCH 09/13] feat: testitem add_info_for_list --- apps/qm/views.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/apps/qm/views.py b/apps/qm/views.py index 522c6cb3..72bca814 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -3,7 +3,8 @@ from rest_framework.decorators import action from rest_framework.exceptions import ParseError from rest_framework.views import APIView from rest_framework.serializers import Serializer -from apps.qm.models import QuaStat, TestItem, Ftest, Ptest, FtestWork +from apps.qm.models import QuaStat, NotOkOption, Ftest, Ptest, FtestWork +from apps.qm.models import TestItem, Defect, Qct, QctTestItem, QctMat, QctDefect from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer, FtestSerializer, PtestSerializer, \ FtestWorkCreateUpdateSerializer, FtestWorkSerializer, DefectSerializer, QctSerializer, QctTestItemSerializer, QctDefectSerializer, QctMatSerializer, \ QctDetailSerializer @@ -16,7 +17,6 @@ from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.wpm.models import SfLog from apps.qm.filters import QuaStatFilter, TestItemFilter, FtestWorkFilter, QctFilter from django.db import transaction -from apps.qm.models import NotOkOption, Defect, Qct, QctTestItem, QctMat, QctDefect from apps.qm.services import ftestwork_submit from apps.utils.thread import MyThread from apps.wpm.services_2 import get_alldata_with_batch_and_store @@ -103,6 +103,18 @@ class TestItemViewSet(CustomModelViewSet): search_fields = ['tags', 'name', 'number', 'mcate_tags'] ordering = ['id'] + def add_info_for_list(self, data): + affects_list = [i['affects'] for i in data] + affectIds = [] + for item in affects_list: + affectIds.extend(item) + affects = TestItem.objects.filter(id__in=affectIds).values_list('id', 'name') + affects_dict = dict(affects) + for item in data: + affects = item["affects"] + item["affects_name"] = ";".join([affects_dict.get(x, '未知') for x in affects]) + return data + class QuaStatViewSet(ListModelMixin, BulkUpdateModelMixin, CustomGenericViewSet): """ From 4eb8aeca964d64f7855280a97488ce8cf49d5835 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 23 Dec 2024 10:52:14 +0800 Subject: [PATCH 10/13] =?UTF-8?q?feat:=20qct=E5=A2=9E=E5=8A=A0=E7=AD=9B?= =?UTF-8?q?=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/qm/filters.py | 7 ++++- apps/qm/migrations/0031_auto_20241223_1050.py | 29 +++++++++++++++++++ apps/qm/models.py | 6 ++-- 3 files changed, 38 insertions(+), 4 deletions(-) create mode 100644 apps/qm/migrations/0031_auto_20241223_1050.py diff --git a/apps/qm/filters.py b/apps/qm/filters.py index 4aba5326..71585306 100644 --- a/apps/qm/filters.py +++ b/apps/qm/filters.py @@ -20,7 +20,12 @@ class QctFilter(filters.FilterSet): class Meta: model = Qct - fields = ["testitems", "defects"] + fields = { + "testitems": ["exact"], + "defects": ["exact"], + "qctmat__material": ["exact"], + "qctmat__tracing": ["exact"], + } class TestItemFilter(filters.FilterSet): tags__contains = filters.CharFilter(field_name='tags', lookup_expr='contains') diff --git a/apps/qm/migrations/0031_auto_20241223_1050.py b/apps/qm/migrations/0031_auto_20241223_1050.py new file mode 100644 index 00000000..63e6fb81 --- /dev/null +++ b/apps/qm/migrations/0031_auto_20241223_1050.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.12 on 2024-12-23 02:50 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0030_auto_20241220_1544'), + ] + + operations = [ + migrations.AlterField( + model_name='qctdefect', + name='qct', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='qctdefect', to='qm.qct', verbose_name='质检模板'), + ), + migrations.AlterField( + model_name='qctmat', + name='qct', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='qctmat', to='qm.qct', verbose_name='质检模板'), + ), + migrations.AlterField( + model_name='qcttestitem', + name='qct', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='qcttestitem', to='qm.qct', verbose_name='质检模板'), + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index b140d06e..41d05290 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -146,20 +146,20 @@ class Qct(CommonAModel): materials = models.ManyToManyField(Material, verbose_name="物料", blank=True, through='qm.qctmat') class QctTestItem(BaseModel): - qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) + qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE, related_name="qcttestitem") testitem = models.ForeignKey(TestItem, verbose_name="检测项", on_delete=models.CASCADE, null=True, blank=True) note = models.TextField('备注', null=True, blank=True) sort = models.FloatField('排序', default=1) class QctDefect(BaseModel): - qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) + qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE, related_name="qctdefect") defect = models.ForeignKey(Defect, verbose_name="缺陷项", on_delete=models.CASCADE) rule_expression = models.TextField('判定表达式', null=True, blank=True) note = models.TextField('备注', null=True, blank=True) sort = models.FloatField('排序', default=1) class QctMat(BaseModel): - qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE) + qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE, related_name="qctmat") material = models.ForeignKey(Material, verbose_name="物料", on_delete=models.CASCADE) tracing = models.CharField('追溯层级', default=QC_T, choices=QC_TRACE_CHOICES, max_length=20, help_text=str(QC_TRACE_CHOICES)) From 91dacba6682b2ac129fe7f8fff5069ad3001645d Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 23 Dec 2024 15:29:10 +0800 Subject: [PATCH 11/13] fix: QctDetailSerializer bug --- apps/qm/models.py | 12 ++++++++++++ apps/qm/serializers.py | 7 ++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/apps/qm/models.py b/apps/qm/models.py index 41d05290..748139c4 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -145,6 +145,18 @@ class Qct(CommonAModel): defects = models.ManyToManyField(Defect, verbose_name="缺陷项", blank=True, through='qm.qctdefect') materials = models.ManyToManyField(Material, verbose_name="物料", blank=True, through='qm.qctmat') + @property + def qct_testitems(self): + return QctTestItem.objects.filter(qct=self) + + @property + def qct_defects(self): + return QctDefect.objects.filter(qct=self) + + @property + def qct_mats(self): + return QctMat.objects.filter(qct=self) + class QctTestItem(BaseModel): qct = models.ForeignKey(Qct, verbose_name="质检模板", on_delete=models.CASCADE, related_name="qcttestitem") testitem = models.ForeignKey(TestItem, verbose_name="检测项", on_delete=models.CASCADE, null=True, blank=True) diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index 2eb6ccee..80084fee 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -38,6 +38,7 @@ class QctSerializer(CustomModelSerializer): class QctTestItemSerializer(CustomModelSerializer): testitem_name = serializers.CharField(source='testitem.name', read_only=True) + testitem_description = serializers.CharField(source='testitem.description', read_only=True) class Meta: model = QctTestItem fields = '__all__' @@ -55,9 +56,9 @@ class QctMatSerializer(CustomModelSerializer): fields = '__all__' class QctDetailSerializer(CustomModelSerializer): - testitems_ = QctTestItemSerializer(source="testitems", many=True, read_only=True) - defects_ = QctDefectSerializer(source="defects", many=True, read_only=True) - defects_ = DefectSerializer(source="defects", many=True, read_only=True) + qct_testitems = QctTestItemSerializer(many=True, read_only=True) + qct_defects = QctDefectSerializer(many=True, read_only=True) + qct_mats = QctMatSerializer(many=True, read_only=True) class Meta: model = Qct fields = '__all__' From cbcba52ff48d0ee1eeb0523cf6c08f3b1c5b3b03 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 23 Dec 2024 15:55:53 +0800 Subject: [PATCH 12/13] =?UTF-8?q?fix:=20QctTestItemSerializer=20=E7=BB=86?= =?UTF-8?q?=E5=8C=96=E8=BF=94=E5=9B=9E=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/serializers.py | 2 ++ apps/qm/views.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index 80084fee..9bc6351b 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -39,6 +39,8 @@ class QctSerializer(CustomModelSerializer): class QctTestItemSerializer(CustomModelSerializer): testitem_name = serializers.CharField(source='testitem.name', read_only=True) testitem_description = serializers.CharField(source='testitem.description', read_only=True) + testitem_field_type = serializers.CharField(source='testitem.field_type', read_only=True) + testitem_choices = serializers.CharField(source='testitem.choices', read_only=True) class Meta: model = QctTestItem fields = '__all__' diff --git a/apps/qm/views.py b/apps/qm/views.py index 72bca814..1837be9b 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -54,6 +54,7 @@ class QctTestItemViewSet(CustomModelViewSet): perms_map = {"get": "*", "post": "qct.update", "put": "qct.update", "delete": "qct.update"} queryset = QctTestItem.objects.all() serializer_class = QctTestItemSerializer + select_related_fields = ["qct", "testitem"] filterset_fields = ["qct", "testitem"] ordering = ["qct", "sort"] @@ -65,6 +66,7 @@ class QctDefectViewSet(CustomModelViewSet): perms_map = {"get": "*", "post": "qct.update", "put": "qct.update", "delete": "qct.update"} queryset = QctDefect.objects.all() serializer_class = QctDefectSerializer + select_related_fields = ["qct", "defect"] filterset_fields = ["qct", "defect"] ordering = ["qct", "sort"] From 27e3dfa3b3217723775a9230959715e113dbcee9 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 23 Dec 2024 18:31:02 +0800 Subject: [PATCH 13/13] feat: db_ins_mplogx bill_date bug --- apps/enm/tasks.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/enm/tasks.py b/apps/enm/tasks.py index 5773a600..102ee1e7 100644 --- a/apps/enm/tasks.py +++ b/apps/enm/tasks.py @@ -1,5 +1,4 @@ # Create your tasks here -from __future__ import absolute_import, unicode_literals from apps.utils.tasks import CustomTask from celery import shared_task from apps.enm.models import MpLogx, Mpoint, MpointStat, EnStat, EnStat2, Xscript @@ -96,9 +95,9 @@ def db_ins_mplogx(): cursor.execute(query, (bill_date, tuple(batchs))) rows = cursor.fetchall() # 获取数据后保存至本地 if rows: - bill_date = rows[-1][-1] + bill_date_x = rows[-1][-1] db_insert_mplogx_batch(rows) - update_sysconfig({'enm1': {'bill_date': str(bill_date)}}) + update_sysconfig({'enm1': {'bill_date': bill_date_x.strftime('%Y-%m-%d %H:%M:%S')}})