diff --git a/apps/qm/migrations/0008_auto_20230725_1112.py b/apps/qm/migrations/0008_auto_20230725_1112.py new file mode 100644 index 00000000..0e0a6e96 --- /dev/null +++ b/apps/qm/migrations/0008_auto_20230725_1112.py @@ -0,0 +1,33 @@ +# Generated by Django 3.2.12 on 2023-07-25 03:12 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0007_alter_quastat_type'), + ] + + operations = [ + migrations.RemoveField( + model_name='quastat', + name='day_s', + ), + migrations.RemoveField( + model_name='quastat', + name='month_s', + ), + migrations.RemoveField( + model_name='quastat', + name='shift', + ), + migrations.RemoveField( + model_name='quastat', + name='type', + ), + migrations.RemoveField( + model_name='quastat', + name='year_s', + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index 152c2fe8..f553089d 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -1,7 +1,7 @@ from django.db import models from apps.system.models import CommonAModel from apps.utils.models import CommonBDModel -from apps.mtm.models import Material, Shift +from apps.mtm.models import Material, Mgroup, Team from apps.wpm.models import SfLog class TestItem(CommonAModel): @@ -17,15 +17,10 @@ class TestItem(CommonAModel): # Create your models here. class QuaStat(CommonBDModel): """ - 质量数据统计表 需要有belong_dept + 质量数据表 """ - type = models.CharField('统计维度', max_length=50, default='day', help_text='year_s/month_s/month_sf/day_s/sflog') - year_s = models.PositiveSmallIntegerField('班年', null=True, blank=True) - month_s = models.PositiveSmallIntegerField('班月', null=True, blank=True) - day_s = models.PositiveSmallIntegerField('班日', null=True, blank=True) material = models.ForeignKey(Material, verbose_name='关联产物', on_delete=models.CASCADE) sflog = models.ForeignKey(SfLog, verbose_name='关联值班记录', on_delete=models.CASCADE, null=True, blank=True) - shift = models.ForeignKey(Shift, 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) diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index c879172a..d56f1756 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -24,11 +24,6 @@ class QuaStatSerializer(CustomModelSerializer): 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['type'] = 'sflog' - attrs['belong_dept'] = attrs['sflog'].belong_dept - end_time = attrs['sflog'].end_time - end_time_local = localtime(end_time) - attrs['year_s'], attrs['month_s'], attrs['day_s'], attrs['shift'] = end_time_local.year, end_time_local.month, end_time_local.day, attrs['sflog'].shift attrs['rate_pass'] = attrs['num_ok']/attrs['num_test'] return attrs diff --git a/apps/qm/tasks.py b/apps/qm/tasks.py index 9f130a23..e2bdd610 100644 --- a/apps/qm/tasks.py +++ b/apps/qm/tasks.py @@ -4,68 +4,209 @@ from apps.qm.models import QuaStat from apps.utils.tasks import CustomTask from django.db.models import Sum, F, ExpressionWrapper, FloatField, Q -def cal_quastat_type(qs, params_o: dict, type: str): - params = params_o.copy() - v_list = ['belong_dept', 'material', 'testitem', 'year_s', 'month_s', 'day_s', 'shift'] - if type == 'month_sf': - params.pop('day_s') - v_list = ['belong_dept', 'material', 'testitem', 'year_s', 'month_s', 'shift'] - elif type == 'month_s': - params.pop('shift') - params.pop('day_s') - v_list = ['belong_dept', 'material', 'testitem', 'year_s', 'month_s'] - elif type == 'year_s': - params.pop('shift') - params.pop('month_s') - params.pop('day_s') - v_list = ['belong_dept', 'material', 'testitem', 'year_s'] - qs_ = qs.filter(**params).values(*v_list) - results = qs_.annotate( - avg_val_total=Sum(F('val_avg')*F('num_test')), - num_test_1=Sum('num_test'), - num_ok_1=Sum('num_ok')).annotate( - avg_val_1=ExpressionWrapper(F('avg_val_total')/F('num_test_1'), output_field=FloatField()) - # ,rate_pass_1=ExpressionWrapper(F('num_ok_1')/F('num_test_1'), output_field=FloatField()) 不知道为什么算出来是0 - ) - query = """ - SELECT SUM(num_test * val_avg)/SUM(num_test) AS avg_val_1, SUM(num_test) AS num_test_1, SUM(num_ok) AS num_ok_1, SUM(num_ok)/SUM(num_test) as rate_pass_1 - FROM qm_quastat - where year_s = 2023 and month_s = 7 and day_s = 7 and type = 'sflog' - GROUP BY belong_dept_id, material_id, testitem_id - """ - params['type'] = type - for r1 in results: - stat_params = { - 'val_avg': r1['avg_val_1'], - 'num_test': r1['num_test_1'], - 'num_ok': r1['num_ok_1'], - 'rate_pass': r1['num_ok_1']/r1['num_test_1'] - } - qua, is_created = QuaStat.objects.get_or_create( - **params, defaults={**params, **stat_params} - ) - for k in stat_params: - setattr(qua, k, stat_params[k]) - qua.save() +# def cal_quastat_type(qs, params_o: dict, type: str): +# params = params_o.copy() +# v_list = ['belong_dept', 'material', 'testitem', 'year_s', 'month_s', 'day_s', 'shift'] +# if type == 'month_sf': +# params.pop('day_s') +# v_list = ['belong_dept', 'material', 'testitem', 'year_s', 'month_s', 'shift'] +# elif type == 'month_s': +# params.pop('shift') +# params.pop('day_s') +# v_list = ['belong_dept', 'material', 'testitem', 'year_s', 'month_s'] +# elif type == 'year_s': +# params.pop('shift') +# params.pop('month_s') +# params.pop('day_s') +# v_list = ['belong_dept', 'material', 'testitem', 'year_s'] +# qs_ = qs.filter(**params).values(*v_list) +# results = qs_.annotate( +# avg_val_total=Sum(F('val_avg')*F('num_test')), +# num_test_1=Sum('num_test'), +# num_ok_1=Sum('num_ok')).annotate( +# avg_val_1=ExpressionWrapper(F('avg_val_total')/F('num_test_1'), output_field=FloatField()) +# # ,rate_pass_1=ExpressionWrapper(F('num_ok_1')/F('num_test_1'), output_field=FloatField()) 不知道为什么算出来是0 +# ) +# query = """ +# SELECT SUM(num_test * val_avg)/SUM(num_test) AS avg_val_1, SUM(num_test) AS num_test_1, SUM(num_ok) AS num_ok_1, SUM(num_ok)/SUM(num_test) as rate_pass_1 +# FROM qm_quastat +# where year_s = 2023 and month_s = 7 and day_s = 7 and type = 'sflog' +# GROUP BY belong_dept_id, material_id, testitem_id +# """ +# params['type'] = type +# for r1 in results: +# stat_params = { +# 'val_avg': r1['avg_val_1'], +# 'num_test': r1['num_test_1'], +# 'num_ok': r1['num_ok_1'], +# 'rate_pass': r1['num_ok_1']/r1['num_test_1'] +# } +# qua, is_created = QuaStat.objects.get_or_create( +# **params, defaults={**params, **stat_params} +# ) +# for k in stat_params: +# setattr(qua, k, stat_params[k]) +# qua.save() + +# @shared_task(base=CustomTask) +# def cal_quastat(quastatId: str): +# ins = QuaStat.objects.get(id=quastatId) +# qs = QuaStat.objects.filter(type='sflog').exclude(Q(val_avg__isnull=True)|Q(num_test__isnull=True)|Q(num_ok__isnull=True)) +# params = { +# 'testitem': ins.testitem, +# 'material': ins.material, +# 'shift': ins.shift, +# 'belong_dept': ins.belong_dept, +# 'year_s': ins.year_s, +# 'month_s': ins.month_s, +# 'day_s': ins.day_s +# } +# # 日统计 +# cal_quastat_type(qs, params_o=params, type='day_s') +# # 班月统计 +# cal_quastat_type(qs, params_o=params, type='month_sf') +# # 月统计 +# cal_quastat_type(qs, params_o=params, type='month_s') +# # 年统计 +# cal_quastat_type(qs, params_o=params, type='year_s') + @shared_task(base=CustomTask) -def cal_quastat(quastatId: str): - ins = QuaStat.objects.get(id=quastatId) - qs = QuaStat.objects.filter(type='sflog').exclude(Q(val_avg__isnull=True)|Q(num_test__isnull=True)|Q(num_ok__isnull=True)) - params = { - 'testitem': ins.testitem, - 'material': ins.material, - 'shift': ins.shift, - 'belong_dept': ins.belong_dept, - 'year_s': ins.year_s, - 'month_s': ins.month_s, - 'day_s': ins.day_s - } +def cal_quastat_sflog(sflogId: str): + from apps.wpm.models import SfLog + from apps.enm.models import EnStat + from apps.utils.sql import query_all_dict + sflog = SfLog.objects.get(id=sflogId) + mgroup = sflog.mgroup + team = sflog.team + qs = QuaStat.objects.exclude(Q(val_avg__isnull=True)|Q(num_test__isnull=True)|Q(num_ok__isnull=True)) + + year_s, month_s, day_s = sflog.get_ymd + + # 班统计 + qs1_v = qs.filter(sflog=sflog).annotate(material_name=F('material__name'), testitem_name=F('testitem__name')).values('material', 'material_name', 'testitem', 'testitem_name', 'val_avg', 'num_test', 'num_ok', 'rate_pass') + enstat, _ = EnStat.objects.get_or_create(type="sflog", sflog=sflog, + defaults={'type': 'sflog', 'sflog': sflog, 'mgroup': mgroup, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'total_production': 0, 'elec_consume': 0}) + enstat.qua_data = list(qs1_v) + enstat.save() + # 日统计 - cal_quastat_type(qs, params_o=params, type='day_s') + sql_q2 = f"""SELECT +mtma."id" AS material, +mtma."name" AS material_name, +qmt."id" AS testitem, +qmt."name" AS testitem_name, +CAST(SUM(num_test * val_avg) AS FLOAT)/NULLIF(SUM(num_test), 0) AS val_avg, +SUM(num_test) AS num_test, +SUM(num_ok) AS num_ok, +CAST(SUM(num_ok) AS FLOAT)/NULLIF(SUM(num_test),0) AS rate_pass +FROM qm_quastat qmq +LEFT JOIN wpm_sflog sflog on sflog.id = qmq.sflog_id +LEFT JOIN mtm_mgroup mgroup on mgroup.id = sflog.mgroup_id +LEFT JOIN mtm_material mtma on mtma.id = qmq.material_id +LEFT JOIN qm_testitem qmt on qmt.id = qmq.testitem_id +where EXTRACT(year from sflog.end_time) = {year_s} +and EXTRACT(month from sflog.end_time) = {month_s} and EXTRACT(day from sflog.end_time) = {day_s} +and mgroup.id = '{mgroup.id}' +and qmq.val_avg is not NULL +and qmq.num_test is not NULL +and qmq.num_ok is not NULL +GROUP BY mgroup."id", mtma."id", qmt."id", mgroup.sort, mtma.sort, qmt.sort +ORDER BY mgroup.sort, mtma.sort, qmt.sort + """ + res2 = query_all_dict(sql_q2) + enstat, _ = EnStat.objects.get_or_create(type="day_s", mgroup=mgroup, year_s=year_s, month_s=month_s, day_s=day_s, + defaults={'type': 'day_s', 'mgroup': mgroup, 'year_s': year_s, 'month_s': month_s, 'day_s': day_s, 'total_production': 0, 'elec_consume': 0}) + enstat.qua_data = res2 + enstat.save() + + if team: # 班月统计 - cal_quastat_type(qs, params_o=params, type='month_sf') - # 月统计 - cal_quastat_type(qs, params_o=params, type='month_s') - # 年统计 - cal_quastat_type(qs, params_o=params, type='year_s') \ No newline at end of file + sql_q3 = f"""SELECT + mtma."id" AS material, + mtma."name" AS material_name, + qmt."id" AS testitem, + qmt."name" AS testitem_name, + CAST(SUM(num_test * val_avg) AS FLOAT)/NULLIF(SUM(num_test), 0) AS val_avg, + SUM(num_test) AS num_test, + SUM(num_ok) AS num_ok, + CAST(SUM(num_ok) AS FLOAT)/NULLIF(SUM(num_test),0) AS rate_pass + FROM qm_quastat qmq + LEFT JOIN wpm_sflog sflog on sflog.id = qmq.sflog_id + LEFT JOIN mtm_team team on team.id = sflog.team_id + LEFT JOIN mtm_material mtma on mtma.id = qmq.material_id + LEFT JOIN qm_testitem qmt on qmt.id = qmq.testitem_id + where EXTRACT(year from sflog.end_time) = {year_s} + and EXTRACT(month from sflog.end_time) = {month_s} + and team.id = '{team.id}' + and qmq.val_avg is not NULL + and qmq.num_test is not NULL + and qmq.num_ok is not NULL + GROUP BY mgroup."id", mtma."id", qmt."id", mgroup.sort, mtma.sort, qmt.sort + ORDER BY mgroup.sort, mtma.sort, qmt.sort + """ + res3 = query_all_dict(sql_q3) + enstat, _ = EnStat.objects.get_or_create(type="month_sf", mgroup=mgroup, team=team, year_s=year_s, month_s=month_s, + defaults={'type': 'month_sf', 'mgroup': mgroup, 'year_s': year_s, 'month_s': month_s, 'team': team, 'total_production': 0, 'elec_consume': 0}) + enstat.qua_data = res3 + enstat.save() + +# 月统计 + sql_q4 = f"""SELECT +mtma."id" AS material, +mtma."name" AS material_name, +qmt."id" AS testitem, +qmt."name" AS testitem_name, +CAST(SUM(num_test * val_avg) AS FLOAT)/NULLIF(SUM(num_test), 0) AS val_avg, +SUM(num_test) AS num_test, +SUM(num_ok) AS num_ok, +CAST(SUM(num_ok) AS FLOAT)/NULLIF(SUM(num_test),0) AS rate_pass +FROM qm_quastat qmq +LEFT JOIN wpm_sflog sflog on sflog.id = qmq.sflog_id +LEFT JOIN mtm_mgroup mgroup on mgroup.id = sflog.mgroup_id +LEFT JOIN mtm_material mtma on mtma.id = qmq.material_id +LEFT JOIN qm_testitem qmt on qmt.id = qmq.testitem_id +where EXTRACT(year from sflog.end_time) = {year_s} +and EXTRACT(month from sflog.end_time) = {month_s} +and mgroup.id = '{mgroup.id}' +and qmq.val_avg is not NULL +and qmq.num_test is not NULL +and qmq.num_ok is not NULL +GROUP BY mgroup."id", mtma."id", qmt."id", mgroup.sort, mtma.sort, qmt.sort +ORDER BY mgroup.sort, mtma.sort, qmt.sort + """ + res4 = query_all_dict(sql_q4) + enstat, _ = EnStat.objects.get_or_create(type="month_s", mgroup=mgroup, year_s=year_s, month_s=month_s, + defaults={'type': 'month_s', 'mgroup': mgroup, 'year_s': year_s, 'month_s': month_s, 'total_production': 0, 'elec_consume': 0}) + enstat.qua_data = res4 + enstat.save() + +# 年统计 + sql_q5 = f"""SELECT +mtma."id" AS material, +mtma."name" AS material_name, +qmt."id" AS testitem, +qmt."name" AS testitem_name, +CAST(SUM(num_test * val_avg) AS FLOAT)/NULLIF(SUM(num_test), 0) AS val_avg, +SUM(num_test) AS num_test, +SUM(num_ok) AS num_ok, +CAST(SUM(num_ok) AS FLOAT)/NULLIF(SUM(num_test),0) AS rate_pass +FROM qm_quastat qmq +LEFT JOIN wpm_sflog sflog on sflog.id = qmq.sflog_id +LEFT JOIN mtm_mgroup mgroup on mgroup.id = sflog.mgroup_id +LEFT JOIN mtm_material mtma on mtma.id = qmq.material_id +LEFT JOIN qm_testitem qmt on qmt.id = qmq.testitem_id +where EXTRACT(year from sflog.end_time) = {year_s} +and mgroup.id = '{mgroup.id}' +and qmq.val_avg is not NULL +and qmq.num_test is not NULL +and qmq.num_ok is not NULL +GROUP BY mgroup."id", mtma."id", qmt."id", mgroup.sort, mtma.sort, qmt.sort +ORDER BY mgroup.sort, mtma.sort, qmt.sort + """ + res5 = query_all_dict(sql_q5) + enstat, _ = EnStat.objects.get_or_create(type="year_s", mgroup=mgroup, year_s=year_s, + defaults={'type': 'year_s', 'mgroup': mgroup, 'year_s': year_s, 'total_production': 0, 'elec_consume': 0}) + enstat.qua_data = res5 + enstat.save() + \ No newline at end of file diff --git a/apps/qm/views.py b/apps/qm/views.py index 67a78bbf..2cb4b787 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -3,12 +3,13 @@ from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelM from rest_framework.decorators import action from apps.qm.models import QuaStat, TestItem from apps.qm.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer -from apps.qm.tasks import cal_quastat +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.wpm.models import SfLog # Create your views here. class TestItemViewSet(ListModelMixin, CustomGenericViewSet): @@ -25,22 +26,25 @@ class TestItemViewSet(ListModelMixin, CustomGenericViewSet): class QuaStatViewSet(ListModelMixin, BulkUpdateModelMixin, CustomGenericViewSet): """ - list:质量分析报告 + list:质量数据统计 - 质量分析报告 + 质量数据统计 """ perms_map = {'get': '*', 'put': 'quastat.update'} queryset = QuaStat.objects.all() serializer_class = QuaStatSerializer update_serializer_class = QuaStatUpdateSerializer - filterset_fields = ['type', 'year_s', 'month_s', 'day_s', 'material', 'testitem', 'belong_dept', 'sflog', 'sflog__mgroup'] + filterset_fields = ['material', 'testitem', 'belong_dept', 'sflog', 'sflog__mgroup', 'sflog__shift', 'sflog__end_time__year', 'sflog__end_time__month', 'sflog__end_time__day'] select_related_fields = ['belong_dept', 'material', 'testitem'] - ordering = ['belong_dept__sort', 'material__sort', 'testitem__sort', 'year_s', 'month_s', 'day_s'] - + ordering = ['belong_dept__sort', 'material__sort', 'testitem__sort'] - def perform_update(self, serializer): - ins = serializer.save() - cal_quastat.delay(ins.id) - if ins.sflog: # 更新值班记录的质检时间 - ins.sflog.last_test_time = datetime.datetime.now() - ins.sflog.save() \ No newline at end of file + def after_bulk_update(self, objs): + now = datetime.datetime.now() + sflogIds = [] + for i in objs: + sflogIds.append(i['sflog']) + sflogIds = list(set(sflogIds)) + SfLog.objects.filter(id__in=sflogIds).update(last_test_time=now) # 更新质检记录时间 + for sflogId in sflogIds: + cal_quastat_sflog.delay(sflogId) + return super().after_bulk_update(objs) \ No newline at end of file