feat: 增加首件检验

This commit is contained in:
caoqianming 2023-11-02 18:50:26 +08:00
parent b2c201877f
commit 7def29d173
5 changed files with 215 additions and 38 deletions

View File

@ -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,
},
),
]

View File

@ -1,28 +1,65 @@
from django.db import models from django.db import models
from apps.system.models import CommonAModel from apps.system.models import CommonAModel, User
from apps.utils.models import CommonBDModel from apps.utils.models import CommonBDModel, BaseModel
from apps.mtm.models import Material, Mgroup, Team from apps.mtm.models import Material, Mgroup, Team
from apps.wpm.models import SfLog from apps.wpm.models import SfLog
class TestItem(CommonAModel): class TestItem(CommonAModel):
""" """
检验项目 检验项目
""" """
name = models.CharField('名称', max_length=100) name = models.CharField('名称', max_length=100)
sort = models.PositiveSmallIntegerField('排序', default=1) sort = models.PositiveSmallIntegerField('排序', default=1)
description = models.TextField('描述', default='')
class Meta: class Meta:
ordering = ['sort', '-create_time'] ordering = ['sort', '-create_time']
# Create your models here. # Create your models here.
class QuaStat(CommonBDModel): class QuaStat(CommonBDModel):
""" """
质量数据表 质量数据表
""" """
material = models.ForeignKey(Material, verbose_name='关联产物', on_delete=models.CASCADE) material = models.ForeignKey(
sflog = models.ForeignKey(SfLog, verbose_name='关联值班记录', on_delete=models.CASCADE, null=True, blank=True) Material, verbose_name='关联产物', on_delete=models.CASCADE)
testitem = models.ForeignKey(TestItem, 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) val_avg = models.FloatField('平均值', null=True, blank=True)
num_test = models.PositiveSmallIntegerField('检测次数', null=True, blank=True) num_test = models.PositiveSmallIntegerField('检测次数', null=True, blank=True)
num_ok = models.PositiveSmallIntegerField('合格次数', null=True, blank=True) num_ok = models.PositiveSmallIntegerField('合格次数', null=True, blank=True)
rate_pass = models.FloatField('合格率', null=True, blank=True) 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)

View File

@ -1,9 +1,11 @@
from apps.qm.models import QuaStat, TestItem from apps.qm.models import QuaStat, TestItem, Ftest, FtestItem
from apps.utils.constants import EXCLUDE_FIELDS from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE
from apps.utils.serializers import CustomModelSerializer from apps.utils.serializers import CustomModelSerializer
from rest_framework import serializers from rest_framework import serializers
from apps.system.models import Dept, Dictionary from apps.system.models import Dept, Dictionary
from apps.wpm.models import SfLog from apps.wpm.models import SfLog
from django.db import transaction
class TestItemSerializer(CustomModelSerializer): class TestItemSerializer(CustomModelSerializer):
class Meta: class Meta:
@ -11,33 +13,94 @@ class TestItemSerializer(CustomModelSerializer):
fields = '__all__' fields = '__all__'
read_only_fields = EXCLUDE_FIELDS read_only_fields = EXCLUDE_FIELDS
class QuaStatSerializer(CustomModelSerializer): class QuaStatSerializer(CustomModelSerializer):
sflog = serializers.PrimaryKeyRelatedField(label="值班记录", queryset=SfLog.objects.all(), required=True) sflog = serializers.PrimaryKeyRelatedField(
belong_dept_name = serializers.CharField(source='belong_dept.name', read_only=True) label="值班记录", queryset=SfLog.objects.all(), required=True)
material_name = serializers.CharField(source='material.name', read_only=True) belong_dept_name = serializers.CharField(
testitem_name = serializers.CharField(source='testitem.name', read_only=True) source='belong_dept.name', read_only=True)
class Meta: material_name = serializers.CharField(
model = QuaStat source='material.name', read_only=True)
fields = '__all__' testitem_name = serializers.CharField(
read_only_fields = EXCLUDE_FIELDS + ['belong_dept'] source='testitem.name', read_only=True)
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)
class Meta: class Meta:
model = QuaStat model = QuaStat
fields = '__all__' fields = '__all__'
read_only_fields = EXCLUDE_FIELDS + ['belong_dept', 'sflog', 'material', 'testitem'] 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}} 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): def validate(self, attrs):
attrs['rate_pass'] = attrs['num_ok']/attrs['num_test'] attrs['rate_pass'] = attrs['num_ok']/attrs['num_test']
return super().validate(attrs) 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

View File

@ -1,7 +1,7 @@
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter 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/' API_BASE_URL = 'api/qm/'
HTML_BASE_URL = 'qm/' HTML_BASE_URL = 'qm/'
@ -9,6 +9,8 @@ HTML_BASE_URL = 'qm/'
router = DefaultRouter() router = DefaultRouter()
router.register('quastat', QuaStatViewSet, basename='quastat') router.register('quastat', QuaStatViewSet, basename='quastat')
router.register('testitem', TestItemViewSet, basename='testitem') router.register('testitem', TestItemViewSet, basename='testitem')
router.register('ftest', FtestViewSet, basename='Ftest')
urlpatterns = [ urlpatterns = [
path(API_BASE_URL, include(router.urls)), path(API_BASE_URL, include(router.urls)),
] ]

View File

@ -1,17 +1,19 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from apps.qm.models import QuaStat, TestItem from apps.qm.models import QuaStat, TestItem, Ftest
from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer, FtestSerializer
from apps.qm.tasks import cal_quastat_sflog from apps.qm.tasks import cal_quastat_sflog
from rest_framework.response import Response from rest_framework.response import Response
from apps.utils.mixins import BulkCreateModelMixin, BulkUpdateModelMixin from apps.utils.mixins import BulkCreateModelMixin, BulkUpdateModelMixin
import datetime import datetime
from apps.utils.viewsets import CustomGenericViewSet from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet
from apps.wpm.models import SfLog from apps.wpm.models import SfLog
from apps.qm.filters import QuaStatFilter from apps.qm.filters import QuaStatFilter
# Create your views here. # Create your views here.
class TestItemViewSet(ListModelMixin, CustomGenericViewSet): class TestItemViewSet(ListModelMixin, CustomGenericViewSet):
""" """
list:质检项目 list:质检项目
@ -24,6 +26,7 @@ class TestItemViewSet(ListModelMixin, CustomGenericViewSet):
filterset_fields = [] filterset_fields = []
ordering = ['id'] ordering = ['id']
class QuaStatViewSet(ListModelMixin, BulkUpdateModelMixin, CustomGenericViewSet): class QuaStatViewSet(ListModelMixin, BulkUpdateModelMixin, CustomGenericViewSet):
""" """
list:质量数据统计 list:质量数据统计
@ -44,6 +47,18 @@ class QuaStatViewSet(ListModelMixin, BulkUpdateModelMixin, CustomGenericViewSet)
for i in objs: for i in objs:
sflogIds.append(i['sflog']) sflogIds.append(i['sflog'])
sflogIds = list(set(sflogIds)) 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: for sflogId in sflogIds:
cal_quastat_sflog.delay(sflogId) cal_quastat_sflog.delay(sflogId)
class FtestViewSet(CustomModelViewSet):
"""
list:首件检验
首件检验
"""
queryset = Ftest.objects.all()
serializer_class = FtestSerializer
select_related_fields = ['test_user', 'check_user']