From 7def29d173ba80041ce14396e3ea2cb12225d353 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 2 Nov 2023 18:50:26 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E9=A6=96=E4=BB=B6?= =?UTF-8?q?=E6=A3=80=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/qm/migrations/0009_auto_20231102_1758.py | 60 ++++++++++ apps/qm/models.py | 49 +++++++- apps/qm/serializers.py | 113 ++++++++++++++---- apps/qm/urls.py | 6 +- apps/qm/views.py | 25 +++- 5 files changed, 215 insertions(+), 38 deletions(-) create mode 100644 apps/qm/migrations/0009_auto_20231102_1758.py diff --git a/apps/qm/migrations/0009_auto_20231102_1758.py b/apps/qm/migrations/0009_auto_20231102_1758.py new file mode 100644 index 00000000..5df8a382 --- /dev/null +++ b/apps/qm/migrations/0009_auto_20231102_1758.py @@ -0,0 +1,60 @@ +# Generated by Django 3.2.12 on 2023-11-02 09:58 + +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 = [ + ('system', '0002_myschedule'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('qm', '0008_auto_20230725_1112'), + ] + + operations = [ + migrations.CreateModel( + name='Ftest', + 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='删除标记')), + ('test_date', models.DateField(verbose_name='检验日期')), + ('test_group', models.CharField(default='', max_length=20, verbose_name='检验工序集')), + ('is_ok', models.BooleanField(default=False, verbose_name='是否合格')), + ('note', models.TextField(blank=True, default='', verbose_name='备注')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ftest_belong_dept', to='system.dept', verbose_name='所属部门')), + ('check_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ftest_check_user', to=settings.AUTH_USER_MODEL, verbose_name='专检人')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ftest_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('test_user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ftest_test_user', to=settings.AUTH_USER_MODEL, verbose_name='操作人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='ftest_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='testitem', + name='description', + field=models.TextField(default='', verbose_name='描述'), + ), + migrations.CreateModel( + name='FtestItem', + 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='删除标记')), + ('test_val', models.FloatField(blank=True, default=0, verbose_name='测量值')), + ('check_val', models.FloatField(blank=True, null=True, verbose_name='专检测量值')), + ('ftest', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.ftest', verbose_name='关联检验')), + ('testitem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.testitem', verbose_name='质检项目')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index f553089d..05831107 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -1,28 +1,65 @@ from django.db import models -from apps.system.models import CommonAModel -from apps.utils.models import CommonBDModel +from apps.system.models import CommonAModel, User +from apps.utils.models import CommonBDModel, BaseModel from apps.mtm.models import Material, Mgroup, Team from apps.wpm.models import SfLog + class TestItem(CommonAModel): """ 检验项目 """ name = models.CharField('名称', max_length=100) sort = models.PositiveSmallIntegerField('排序', default=1) + description = models.TextField('描述', default='') class Meta: ordering = ['sort', '-create_time'] # Create your models here. + + class QuaStat(CommonBDModel): """ 质量数据表 """ - material = models.ForeignKey(Material, verbose_name='关联产物', on_delete=models.CASCADE) - sflog = models.ForeignKey(SfLog, verbose_name='关联值班记录', on_delete=models.CASCADE, null=True, blank=True) - testitem = models.ForeignKey(TestItem, verbose_name='质检项目', on_delete=models.CASCADE) + material = models.ForeignKey( + Material, verbose_name='关联产物', on_delete=models.CASCADE) + sflog = models.ForeignKey( + SfLog, verbose_name='关联值班记录', on_delete=models.CASCADE, null=True, blank=True) + testitem = models.ForeignKey( + TestItem, verbose_name='质检项目', on_delete=models.CASCADE) val_avg = models.FloatField('平均值', null=True, blank=True) num_test = models.PositiveSmallIntegerField('检测次数', null=True, blank=True) num_ok = models.PositiveSmallIntegerField('合格次数', null=True, blank=True) - rate_pass = models.FloatField('合格率', null=True, blank=True) \ No newline at end of file + rate_pass = models.FloatField('合格率', null=True, blank=True) + + +class Ftest(CommonBDModel): + """ + 首件检验 + """ + test_date = models.DateField('检验日期') + test_group = models.CharField('检验工序集', max_length=20, default='') + test_user = models.ForeignKey( + User, verbose_name='操作人', on_delete=models.CASCADE, related_name='ftest_test_user') + check_user = models.ForeignKey( + User, verbose_name='专检人', on_delete=models.CASCADE, related_name='ftest_check_user') + is_ok = models.BooleanField('是否合格', default=False) + note = models.TextField('备注', default='', blank=True) + + @property + def ftestitems(self): + return FtestItem.objects.filter(ftest=self) + + +class FtestItem(BaseModel): + """ + 检测明细 + """ + ftest = models.ForeignKey( + Ftest, verbose_name='关联检验', on_delete=models.CASCADE) + testitem = models.ForeignKey( + TestItem, verbose_name='质检项目', on_delete=models.CASCADE) + test_val = models.FloatField('测量值', default=0, blank=True) + check_val = models.FloatField('专检测量值', null=True, blank=True) diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index cac65d50..9ad0644c 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -1,9 +1,11 @@ -from apps.qm.models import QuaStat, TestItem -from apps.utils.constants import EXCLUDE_FIELDS +from apps.qm.models import QuaStat, TestItem, Ftest, FtestItem +from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE from apps.utils.serializers import CustomModelSerializer from rest_framework import serializers from apps.system.models import Dept, Dictionary from apps.wpm.models import SfLog +from django.db import transaction + class TestItemSerializer(CustomModelSerializer): class Meta: @@ -11,33 +13,94 @@ class TestItemSerializer(CustomModelSerializer): fields = '__all__' read_only_fields = EXCLUDE_FIELDS + class QuaStatSerializer(CustomModelSerializer): - sflog = serializers.PrimaryKeyRelatedField(label="值班记录", queryset=SfLog.objects.all(), required=True) - belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) - material_name = serializers.CharField(source='material.name', read_only=True) - testitem_name = serializers.CharField(source='testitem.name', read_only=True) - class Meta: - model = QuaStat - fields = '__all__' - read_only_fields = EXCLUDE_FIELDS + ['belong_dept'] - extra_kwargs = {'val_avg': {'required': True, 'allow_null': False}, 'num_test':{'required': True, 'allow_null': False}, 'num_ok': {'required': True, 'allow_null': False}} - - def validate(self, attrs): - attrs['rate_pass'] = attrs['num_ok']/attrs['num_test'] - attrs['belong_dept'] = attrs['sflog'].mgroup.belong_dept - return attrs - -class QuaStatUpdateSerializer(CustomModelSerializer): - belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) - material_name = serializers.CharField(source='material.name', read_only=True) - testitem_name = serializers.CharField(source='testitem.name', read_only=True) + sflog = serializers.PrimaryKeyRelatedField( + label="值班记录", queryset=SfLog.objects.all(), required=True) + belong_dept_name = serializers.CharField( + source='belong_dept.name', read_only=True) + material_name = serializers.CharField( + source='material.name', read_only=True) + testitem_name = serializers.CharField( + source='testitem.name', read_only=True) class Meta: model = QuaStat fields = '__all__' - read_only_fields = EXCLUDE_FIELDS + ['belong_dept', 'sflog', 'material', 'testitem'] - extra_kwargs = {'val_avg': {'required': True, 'allow_null': False}, 'num_test':{'required': True, 'allow_null': False}, 'num_ok': {'required': True, 'allow_null': False}} - + read_only_fields = EXCLUDE_FIELDS + ['belong_dept'] + extra_kwargs = {'val_avg': {'required': True, 'allow_null': False}, 'num_test': { + 'required': True, 'allow_null': False}, 'num_ok': {'required': True, 'allow_null': False}} + def validate(self, attrs): attrs['rate_pass'] = attrs['num_ok']/attrs['num_test'] - return super().validate(attrs) \ No newline at end of file + attrs['belong_dept'] = attrs['sflog'].mgroup.belong_dept + return attrs + + +class QuaStatUpdateSerializer(CustomModelSerializer): + belong_dept_name = serializers.CharField( + source='belong_dept.name', read_only=True) + material_name = serializers.CharField( + source='material.name', read_only=True) + testitem_name = serializers.CharField( + source='testitem.name', read_only=True) + + class Meta: + model = QuaStat + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + \ + ['belong_dept', 'sflog', 'material', 'testitem'] + extra_kwargs = {'val_avg': {'required': True, 'allow_null': False}, 'num_test': { + 'required': True, 'allow_null': False}, 'num_ok': {'required': True, 'allow_null': False}} + + def validate(self, attrs): + attrs['rate_pass'] = attrs['num_ok']/attrs['num_test'] + return super().validate(attrs) + + +class FtestItemSerializer(CustomModelSerializer): + testitem_name = serializers.CharField( + source='testitem.name', read_only=True) + testitem_description = serializers.CharField( + source='testitem.description', read_only=True) + + class Meta: + model = FtestItem + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS_BASE + + +class FtestSerializer(CustomModelSerializer): + belong_dept = serializers.PrimaryKeyRelatedField( + required=True, queryset=Dept.objects.all()) + test_user_name = serializers.CharField( + source='test_user.name', read_only=True) + check_user_name = serializers.CharField( + source='check_user.name', read_only=True) + ftestitems = FtestItemSerializer(label='检验明细', many=True) + + class Meta: + model = Ftest + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + + def create(self, validated_data): + ftestitems = validated_data.pop('ftestitems', []) + with transaction.atomic(): + instance = super().create(validated_data) + for item in ftestitems: + FtestItem.objects.create(ftest=instance, **item) + return instance + + def update(self, instance, validated_data): + ftestitems = validated_data.pop('ftestitems', []) + with transaction.atomic(): + instance = super().update(instance, validated_data) + for item in ftestitems: + id = item.get('id', None) + if id: + ftestitem = FtestItem.objects.get(id=id) + ftestitem.test_val = item['test_val'] + ftestitem.check_val = item['check_val'] + ftestitem.save() + return instance diff --git a/apps/qm/urls.py b/apps/qm/urls.py index b986fab8..bf5de1df 100644 --- a/apps/qm/urls.py +++ b/apps/qm/urls.py @@ -1,7 +1,7 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.qm.views import QuaStatViewSet, TestItemViewSet +from apps.qm.views import QuaStatViewSet, TestItemViewSet, FtestViewSet API_BASE_URL = 'api/qm/' HTML_BASE_URL = 'qm/' @@ -9,6 +9,8 @@ HTML_BASE_URL = 'qm/' router = DefaultRouter() router.register('quastat', QuaStatViewSet, basename='quastat') router.register('testitem', TestItemViewSet, basename='testitem') +router.register('ftest', FtestViewSet, basename='Ftest') + urlpatterns = [ path(API_BASE_URL, include(router.urls)), -] \ No newline at end of file +] diff --git a/apps/qm/views.py b/apps/qm/views.py index 400d98b1..49efdb35 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -1,17 +1,19 @@ from django.shortcuts import render from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin from rest_framework.decorators import action -from apps.qm.models import QuaStat, TestItem -from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer +from apps.qm.models import QuaStat, TestItem, Ftest +from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer, FtestSerializer from apps.qm.tasks import cal_quastat_sflog from rest_framework.response import Response from apps.utils.mixins import BulkCreateModelMixin, BulkUpdateModelMixin import datetime -from apps.utils.viewsets import CustomGenericViewSet +from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from apps.wpm.models import SfLog from apps.qm.filters import QuaStatFilter # Create your views here. + + class TestItemViewSet(ListModelMixin, CustomGenericViewSet): """ list:质检项目 @@ -24,6 +26,7 @@ class TestItemViewSet(ListModelMixin, CustomGenericViewSet): filterset_fields = [] ordering = ['id'] + class QuaStatViewSet(ListModelMixin, BulkUpdateModelMixin, CustomGenericViewSet): """ list:质量数据统计 @@ -44,6 +47,18 @@ class QuaStatViewSet(ListModelMixin, BulkUpdateModelMixin, CustomGenericViewSet) for i in objs: sflogIds.append(i['sflog']) sflogIds = list(set(sflogIds)) - SfLog.objects.filter(id__in=sflogIds).update(last_test_time=now) # 更新质检记录时间 + SfLog.objects.filter(id__in=sflogIds).update( + last_test_time=now) # 更新质检记录时间 for sflogId in sflogIds: - cal_quastat_sflog.delay(sflogId) \ No newline at end of file + cal_quastat_sflog.delay(sflogId) + + +class FtestViewSet(CustomModelViewSet): + """ + list:首件检验 + + 首件检验 + """ + queryset = Ftest.objects.all() + serializer_class = FtestSerializer + select_related_fields = ['test_user', 'check_user']