This commit is contained in:
zty 2024-12-24 09:26:59 +08:00
commit aa3ba099be
13 changed files with 366 additions and 17 deletions

View File

@ -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')}})

View File

@ -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='排序'),
),
]

View File

@ -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)

View File

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

View File

@ -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,17 @@ 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": ["exact"],
"defects": ["exact"],
"qctmat__material": ["exact"],
"qctmat__tracing": ["exact"],
}
class TestItemFilter(filters.FilterSet):
tags__contains = filters.CharFilter(field_name='tags', lookup_expr='contains')

View File

@ -0,0 +1,102 @@
# Generated by Django 3.2.12 on 2024-12-19 07:09
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('mtm', '0048_auto_20241218_1431'),
('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='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=[
('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='物料')),
('qct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.qct', verbose_name='质检模板')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
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='删除标记')),
('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(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='质检模板')),
],
options={
'abstract': False,
},
),
migrations.AddField(
model_name='qct',
name='defects',
field=models.ManyToManyField(blank=True, through='qm.QctDefect', 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.QctTestItem', 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='最后编辑人'),
),
]

View File

@ -0,0 +1,28 @@
# Generated by Django 3.2.12 on 2024-12-20 07:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0029_auto_20241219_1509'),
]
operations = [
migrations.AddField(
model_name='testitem',
name='affects',
field=models.JSONField(blank=True, default=list, verbose_name='影响项列表'),
),
migrations.AddField(
model_name='testitem',
name='formula',
field=models.TextField(blank=True, null=True, verbose_name='计算公式'),
),
migrations.AddField(
model_name='testitem',
name='readonly',
field=models.BooleanField(default=False, verbose_name='只读'),
),
]

View File

@ -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='质检模板'),
),
]

View File

@ -21,6 +21,7 @@ class Defect(CommonAModel):
def __str__(self):
return self.name
class NotOkOption(models.TextChoices):
# 不合格项
zw = "zw", _("炸纹")
@ -119,11 +120,62 @@ 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']
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.qcttestitem')
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)
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, 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, 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))
class QuaStat(CommonBDModel):
"""
质量数据表

View File

@ -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, QctTestItem, QctMat, QctDefect)
from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE
from apps.utils.serializers import CustomModelSerializer
from rest_framework import serializers
@ -29,6 +30,41 @@ 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 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__'
class QctDefectSerializer(CustomModelSerializer):
defect_name = serializers.CharField(source='defect.name', read_only=True)
class Meta:
model = QctDefect
fields = '__all__'
class QctMatSerializer(CustomModelSerializer):
material_name = serializers.StringRelatedField(source='material', read_only=True)
class Meta:
model = QctMat
fields = '__all__'
class QctDetailSerializer(CustomModelSerializer):
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__'
read_only_fields = EXCLUDE_FIELDS
class QuaStatSerializer(CustomModelSerializer):
sflog = serializers.PrimaryKeyRelatedField(

View File

@ -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, QctTestItemViewSet, QctDefectViewSet, QctMatViewSet)
API_BASE_URL = 'api/qm/'
HTML_BASE_URL = 'qm/'
@ -15,6 +15,10 @@ 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('qcttestitem', QctTestItemViewSet, basename='qcttestitem')
router.register('qctdefect', QctDefectViewSet, basename="qctdefect")
router.register('qctmat', QctMatViewSet, basename='qctmat')
urlpatterns = [
path(API_BASE_URL, include(router.urls)),
path(API_BASE_URL + 'notok_option/', NotOkOptionView.as_view()),

View File

@ -3,9 +3,11 @@ 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
FtestWorkCreateUpdateSerializer, FtestWorkSerializer, DefectSerializer, QctSerializer, QctTestItemSerializer, QctDefectSerializer, QctMatSerializer, \
QctDetailSerializer
from apps.qm.tasks import cal_quastat_sflog
from rest_framework.response import Response
from apps.utils.mixins import BulkUpdateModelMixin
@ -13,9 +15,8 @@ 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
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:缺陷项
缺陷项
缺陷项
"""
@ -33,6 +34,52 @@ class DefectViewSet(CustomModelViewSet):
filterset_fields = ["cate", "okcate"]
search_fields = ["name", "code"]
class QctViewSet(CustomModelViewSet):
"""
检测模板
检测模板
"""
queryset = Qct.objects.all()
serializer_class = QctSerializer
retrieve_serializer_class = QctDetailSerializer
filterset_class = QctFilter
search_fields = ["name", "number"]
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"]
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"]
class QctMatViewSet(CustomModelViewSet):
"""检测物料
检测物料
"""
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': '*'}
@ -58,6 +105,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):
"""

View File

@ -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)