diff --git a/apps/mtm/migrations/0046_process_mtype.py b/apps/mtm/migrations/0046_process_mtype.py new file mode 100644 index 00000000..ebbdfca3 --- /dev/null +++ b/apps/mtm/migrations/0046_process_mtype.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2024-12-17 06:14 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0045_process_type'), + ] + + operations = [ + migrations.AddField( + model_name='process', + name='mtype', + field=models.PositiveSmallIntegerField(choices=[(10, '常规'), (20, '切分'), (30, '合并')], default=10, verbose_name='工序生产类型'), + ), + ] diff --git a/apps/mtm/migrations/0047_route_div_number.py b/apps/mtm/migrations/0047_route_div_number.py new file mode 100644 index 00000000..072fc4ce --- /dev/null +++ b/apps/mtm/migrations/0047_route_div_number.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.12 on 2024-12-18 00:55 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0046_process_mtype'), + ] + + operations = [ + migrations.AddField( + model_name='route', + name='div_number', + field=models.PositiveSmallIntegerField(blank=True, default=1, verbose_name='切分数量'), + ), + ] diff --git a/apps/mtm/models.py b/apps/mtm/models.py index 83624892..193888c3 100644 --- a/apps/mtm/models.py +++ b/apps/mtm/models.py @@ -1,7 +1,6 @@ from django.db import models from apps.system.models import CommonAModel, Dictionary, CommonBModel, CommonADModel, File, BaseModel -from django.db.models import Subquery, OuterRef -from rest_framework.exceptions import ValidationError, ParseError +from rest_framework.exceptions import ParseError from apps.utils.models import CommonBDModel class Process(CommonBModel): @@ -10,8 +9,14 @@ class Process(CommonBModel): """ PRO_PROD = 10 RPO_TEST = 20 + + + PRO_NORMAL = 10 + PRO_DIV = 20 + PRO_MERGE = 30 name = models.CharField('工序名称', max_length=100) type = models.PositiveSmallIntegerField("工序类型", default=PRO_PROD, choices=((PRO_PROD, '生产工序'), (RPO_TEST, '检验工序'))) + mtype = models.PositiveSmallIntegerField("工序生产类型", default=PRO_NORMAL, choices=((PRO_NORMAL, '常规'), (PRO_DIV, '切分'), (PRO_MERGE, '合并'))) cate = models.CharField('大类', max_length=10, default='') sort = models.PositiveSmallIntegerField('排序', default=1) instruction = models.ForeignKey( @@ -221,6 +226,7 @@ class Route(CommonADModel): Material, verbose_name='主要输出物料', on_delete=models.CASCADE, related_name='route_material_out', null=True, blank=True) is_count_utask = models.BooleanField('是否主任务统计', default=False) out_rate = models.FloatField('出材率', default=100, blank=True) + div_number = models.PositiveSmallIntegerField('切分数量', default=1, blank=True) hour_work = models.FloatField('工时', null=True, blank=True) batch_bind = models.BooleanField('是否绑定批次', default=True) diff --git a/apps/mtm/serializers.py b/apps/mtm/serializers.py index 6f7a72c9..cf41fa79 100644 --- a/apps/mtm/serializers.py +++ b/apps/mtm/serializers.py @@ -170,8 +170,11 @@ class RouteSerializer(CustomModelSerializer): attrs['material'] = attrs['routepack'].material if 'mgroup' in attrs and attrs['mgroup']: attrs['process'] = attrs['mgroup'].process - if attrs.get('process', None) is None: + process: Process = attrs.get('process', None) + if process is None: raise ParseError('未提供操作工序') + if process.mtype == Process.PRO_DIV and attrs.get('div_number', 1) <= 1: + raise ParseError('切分数量必须大于1') return super().validate(attrs) def gen_material_out(self, instance: Route): diff --git a/apps/pm/services.py b/apps/pm/services.py index d54315a6..7e3213df 100644 --- a/apps/pm/services.py +++ b/apps/pm/services.py @@ -25,7 +25,8 @@ class PmService: while indx < rate_len: if indx + 1 == rate_len: # 循环到最后一步 break - xcount = xcount/(rate_list[indx+1]/100) + rate, div_number = rate_list[indx+1] + xcount = xcount/(rate/100)/div_number indx = indx + 1 r_list.append(math.ceil(xcount)) return r_list @@ -130,7 +131,7 @@ class PmService: if not rqs.exists(): raise ParseError('未配置工艺路线') # 通过出材率校正任务数, out_rate 默认为 100 - out_rate_list = [rq.out_rate for rq in rqs] + out_rate_list = [(rq.out_rate, rq.div_number) for rq in rqs] count_task_list = cls.cal_real_task_count(count,out_rate_list) # 创建小任务 for ind, val in enumerate(rqs): diff --git a/apps/qm/migrations/0028_defect.py b/apps/qm/migrations/0028_defect.py new file mode 100644 index 00000000..0ae84cd7 --- /dev/null +++ b/apps/qm/migrations/0028_defect.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.12 on 2024-12-17 01:38 + +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), + ('qm', '0027_ftestwork_ticket'), + ] + + operations = [ + migrations.CreateModel( + name='Defect', + 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='名称')), + ('code', models.CharField(max_length=50, verbose_name='标识')), + ('cate', models.CharField(choices=[('尺寸', '尺寸'), ('外观', '外观'), ('内质', '内质')], max_length=50, verbose_name='分类')), + ('okcate', models.PositiveSmallIntegerField(choices=[(10, '合格'), (20, '合格B类'), (30, '不合格')], default=30, verbose_name='不合格分类')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='defect_create_by', 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='defect_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/apps/qm/models.py b/apps/qm/models.py index 7be55065..931f183c 100644 --- a/apps/qm/models.py +++ b/apps/qm/models.py @@ -1,11 +1,26 @@ from django.db import models -from apps.system.models import CommonAModel, CommonADModel, User +from apps.system.models import CommonAModel, User from apps.utils.models import CommonBDModel, BaseModel -from apps.mtm.models import Material, Mgroup, Team, Shift +from apps.mtm.models import Material, Shift from apps.em.models import Equipment from apps.wpm.models import SfLog, WMaterial from django.utils.translation import gettext_lazy as _ +class Defect(CommonAModel): + # 缺陷项 + DEFECT_OK = 10 + DEFECT_OK_B = 20 + DEFECT_NOTOK = 30 + name = models.CharField(max_length=50, verbose_name="名称") + code = models.CharField(max_length=50, verbose_name="标识") + cate = models.CharField(max_length=50, verbose_name="分类", choices=(("尺寸", "尺寸"), ("外观", "外观"), ("内质", "内质"))) + okcate= models.PositiveSmallIntegerField(verbose_name="不合格分类", + choices=((DEFECT_OK, "合格"), (DEFECT_OK_B, "合格B类"), (DEFECT_NOTOK, "不合格")), + default=DEFECT_NOTOK) + + def __str__(self): + return self.name + class NotOkOption(models.TextChoices): # 不合格项 zw = "zw", _("炸纹") @@ -85,6 +100,7 @@ FTEST_TYPE_CHOICES = ( ('process', '过程检验'), ('prod', '成品检验') ) + class TestItem(CommonAModel): """ 检测项目 diff --git a/apps/qm/serializers.py b/apps/qm/serializers.py index 877ea786..66f95b38 100644 --- a/apps/qm/serializers.py +++ b/apps/qm/serializers.py @@ -1,13 +1,27 @@ -from apps.qm.models import QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest, NotOkOption +from apps.qm.models import QuaStat, TestItem, Ftest, FtestItem, FtestWork, Ptest, NotOkOption, Defect from apps.utils.constants import EXCLUDE_FIELDS, EXCLUDE_FIELDS_BASE from apps.utils.serializers import CustomModelSerializer from rest_framework import serializers from rest_framework.exceptions import ValidationError -from apps.system.models import Dept, Dictionary from apps.wpm.models import SfLog, WMaterial from django.db import transaction from apps.inm.serializers import MaterialBatchDetailSerializer +class DefectSerializer(CustomModelSerializer): + class Meta: + model = Defect + fields = '__all__' + read_only_fields = EXCLUDE_FIELDS + + def create(self, validated_data): + code = validated_data["code"] + if Defect.objects.get_queryset(all=True).filter(code=code).exists(): + raise ValidationError("缺陷标识已存在") + return super().create(validated_data) + + def update(self, instance, validated_data): + validated_data.pop("code", None) + return super().update(instance, validated_data) class TestItemSerializer(CustomModelSerializer): class Meta: diff --git a/apps/qm/services.py b/apps/qm/services.py index 53855959..523d034e 100644 --- a/apps/qm/services.py +++ b/apps/qm/services.py @@ -5,6 +5,8 @@ from rest_framework.exceptions import ParseError from django.utils import timezone from apps.wf.models import Ticket from apps.qm.models import NotOkOption +from apps.utils.thread import MyThread +from apps.wpm.services_2 import get_alldata_with_batch_and_store def ftestwork_submit_validate(ins: FtestWork): wm:WMaterial = ins.wm @@ -113,4 +115,6 @@ def bind_ftestwork(ticket: Ticket, transition, new_ticket_data: dict): def ftestwork_audit_end(ticket: Ticket): ins = FtestWork.objects.get(id=ticket.ticket_data['t_id']) - ftestwork_submit(ins, ticket.create_by) \ No newline at end of file + ftestwork_submit(ins, ticket.create_by) + if ins.batch: + MyThread(target=get_alldata_with_batch_and_store, args=(ins.batch,)).start() \ No newline at end of file diff --git a/apps/qm/urls.py b/apps/qm/urls.py index ed5608c3..a0f5c777 100644 --- a/apps/qm/urls.py +++ b/apps/qm/urls.py @@ -1,7 +1,9 @@ from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.qm.views import QuaStatViewSet, TestItemViewSet, FtestWorkViewSet, FtestViewSet, PtestViewSet, NotOkOptionView +from apps.qm.views import (QuaStatViewSet, TestItemViewSet, + FtestWorkViewSet, FtestViewSet, PtestViewSet, + NotOkOptionView, DefectViewSet) API_BASE_URL = 'api/qm/' HTML_BASE_URL = 'qm/' @@ -12,6 +14,7 @@ router.register('testitem', TestItemViewSet, basename='testitem') router.register('ftest', FtestViewSet, basename='ftest') router.register('ftestwork', FtestWorkViewSet, basename='ftestwork') router.register('ptest', PtestViewSet, basename='ptest') +router.register("defect", DefectViewSet, basename="defect") 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 89370725..fa803a8c 100644 --- a/apps/qm/views.py +++ b/apps/qm/views.py @@ -1,27 +1,38 @@ -from django.shortcuts import render -from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin +from rest_framework.mixins import ListModelMixin 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.serializers import QuaStatSerializer, TestItemSerializer, QuaStatUpdateSerializer, FtestSerializer, PtestSerializer, \ - FtestWorkCreateUpdateSerializer, FtestWorkSerializer + FtestWorkCreateUpdateSerializer, FtestWorkSerializer, DefectSerializer from apps.qm.tasks import cal_quastat_sflog from rest_framework.response import Response -from apps.utils.mixins import BulkCreateModelMixin, BulkUpdateModelMixin +from apps.utils.mixins import BulkUpdateModelMixin import datetime 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 +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 +from apps.wf.models import State # Create your views here. +class DefectViewSet(CustomModelViewSet): + """ + list:缺陷项 + + 缺陷项 + """ + queryset = Defect.objects.all() + serializer_class = DefectSerializer + filterset_fields = ["cate", "okcate"] + search_fields = ["name", "code"] + class NotOkOptionView(APIView): perms_map = {'get': '*'} @@ -146,6 +157,8 @@ class FtestWorkViewSet(CustomModelViewSet): ins:FtestWork = self.get_object() if ins.submit_time is not None: raise ParseError('已提交无法修改') + if ins.ticket and ins.ticket.state.type != State.STATE_TYPE_START: + raise ParseError('审批单已进行,无法修改') x = super().update(request, *args, **kwargs) # 触发批次统计分析 if ins.batch: @@ -156,6 +169,8 @@ class FtestWorkViewSet(CustomModelViewSet): ins:FtestWork = self.get_object() if ins.submit_time is not None: raise ParseError('已提交无法删除') + if ins.ticket: + raise ParseError('存在审批, 无法删除') x = super().destroy(request, *args, **kwargs) # 触发批次统计分析 if ins.batch: @@ -177,6 +192,8 @@ class FtestWorkViewSet(CustomModelViewSet): 提交检验工作 """ ins:FtestWork = self.get_object() + if ins.ticket: + raise ParseError('该检验工作存在审批!') if ins.wm is None: raise ParseError('该检验工作未关联车间库存') if ins.submit_time is None: diff --git a/apps/system/serializers.py b/apps/system/serializers.py index d95dd3f5..ad2cb6a9 100755 --- a/apps/system/serializers.py +++ b/apps/system/serializers.py @@ -225,6 +225,18 @@ class PermissionSerializer(CustomModelSerializer): class Meta: model = Permission fields = '__all__' + + def validate(self, attrs): + type = attrs["type"] + if type in [Permission.PERM_TYPE_MODULE, Permission.PERM_TYPE_API]: + attrs.pop("component", None) + attrs.pop("is_hidden", None) + attrs.pop("is_fullpage", None) + if type == Permission.PERM_TYPE_API: + attrs.pop("route_name", None) + attrs.pop("icon", None) + attrs.pop("path", None) + return super().validate(attrs) class PermissionCreateUpdateSerializer(CustomModelSerializer): diff --git a/apps/system/views.py b/apps/system/views.py index ac1e6a7d..a0b4b811 100755 --- a/apps/system/views.py +++ b/apps/system/views.py @@ -44,6 +44,7 @@ from drf_yasg.utils import swagger_auto_schema from server.settings import get_sysconfig, update_sysconfig, update_dict from apps.utils.constants import DEFAULT_PWD from django.core.cache import cache +from apps.utils.permission import get_user_route # logger.info('请求成功! response_code:{};response_headers:{}; # response_body:{}'.format(response_code, response_headers, response_body[:251])) @@ -543,6 +544,14 @@ class UserViewSet(CustomModelViewSet): """ user = request.user return Response(UserFullInfoSerializer(user).data) + + @action(methods=['get'], detail=False, permission_classes=[IsAuthenticated]) + def route(self, request, pk=None): + """登录用户路由 + + 获取登录用户路由 + """ + return Response(get_user_route(request.user)) @action(methods=['post'], detail=False, permission_classes=[IsAuthenticated]) def bind_wxmp(self, request, pk=None): diff --git a/apps/utils/permission.py b/apps/utils/permission.py index d0d19fde..bf4a9781 100755 --- a/apps/utils/permission.py +++ b/apps/utils/permission.py @@ -4,6 +4,8 @@ from apps.utils.queryset import get_child_queryset2 from apps.system.models import DataFilter, Dept, Permission, PostRole, UserPost, User from django.db.models.query import QuerySet from typing import List +from apps.utils.tools import build_tree_from_list +from django.db.models import Q # 后端代码里有的权限标识 ALL_PERMS = [ @@ -21,6 +23,42 @@ def get_alld_perms(update_cache=False) -> List[str]: cache.set(key, perms_alld_list, timeout=60*5) return perms_alld_list +def get_user_route(user: User) -> List[str]: + """ + 获取用户PC前端路由 + """ + perm_qs = Permission.objects.filter( + type__in=[Permission.PERM_TYPE_MODULE, Permission.PERM_TYPE_PAGE]).exclude( + Q(path=None) | Q(path='')| Q(route_name=None)|Q(route_name='')) + user_routes_qs = None + if user.is_superuser: + user_routes_qs = perm_qs + else: + user_routes_qs = perm_qs.filter(role_perms__in=PostRole.objects.filter( + post__in=UserPost.objects.filter(user=user).values_list("post", flat=True)).values_list("role", flat=True)) + user_routes_qs = user_routes_qs.order_by('sort') + user_routes_list = list(user_routes_qs.values("id", "name", "type", "route_name", "icon", "path", "component", "is_hidden", "is_fullpage", "parent")) + for item in user_routes_list: + item["meta"] = {} + item["meta"]["title"] = item["name"] + item.pop("name") + item["meta"]["icon"] = item["icon"] + item.pop("icon") + if item["type"] == Permission.PERM_TYPE_MODULE: + item["meta"]["type"] = "menu" + item.pop("component", None) + item.pop("type") + item["meta"]["hidden"] = item["is_hidden"] + item.pop("is_hidden") + item["meta"]["fullpage"] = item["is_fullpage"] + item.pop("is_fullpage") + item["name"] = item["route_name"] + item.pop("route_name") + return build_tree_from_list(user_routes_list) + + + + def get_user_perms_map(user, update_cache=False): """ 获取权限字典,可用redis存取(包括功能和数据权限) diff --git a/apps/utils/tools.py b/apps/utils/tools.py index 10dce896..c19ae87e 100755 --- a/apps/utils/tools.py +++ b/apps/utils/tools.py @@ -290,3 +290,21 @@ def compare_values(val1, val2, ignore_order=False): return compare_dicts(val1, val2, ignore_order) else: return val1 == val2 + + +def build_tree_from_list(data, parent_field="parent"): + id_map = {item["id"]: item for item in data} + tree = [] + + for item in data: + parent_id = item.get(parent_field, None) + if parent_id is None: + tree.append(item) + else: + parent = id_map.get(parent_id, None) + if parent: + parent.setdefault("children", []).append(item) + else: + tree.append(item) + + return tree \ No newline at end of file diff --git a/apps/wpm/services.py b/apps/wpm/services.py index 8725c4b5..3b881029 100644 --- a/apps/wpm/services.py +++ b/apps/wpm/services.py @@ -265,6 +265,12 @@ def mlog_submit(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): mlog.stored_mgroup = stored_mgroup mlog.save() + # 更新任务进度 + cal_mtask_progress_from_mlog(mlog) + + # 更新物料数量 + MyThread(target=cal_material_count_from_mlog,args=(mlog,)).start() + # 触发批次统计分析 if mlog.batch: MyThread(target=get_alldata_with_batch_and_store, args=(mlog.batch,)).start() @@ -386,10 +392,32 @@ def mlog_revert(mlog: Mlog, user: User, now: Union[datetime.datetime, None]): if update_mtaskIds: Mtask.objects.filter(id__in=update_mtaskIds, state=Mtask.MTASK_SUBMIT).update(state=Mtask.MTASK_ASSGINED) + # 更新任务进度 + cal_mtask_progress_from_mlog(mlog) + + # 更新物料数量 + MyThread(target=cal_material_count_from_mlog,args=(mlog,)).start() + # 触发批次统计分析 if mlog.batch: MyThread(target=get_alldata_with_batch_and_store, args=(mlog.batch,)).start() +def cal_mtask_progress_from_mlog(mlog): + """ + 更新mlog关联的任务进度(可线程中执行) + """ + if mlog.fill_way in [Mlog.MLOG_2, Mlog.MLOG_12] and mlog.mtask: + update_mtask(mlog.mtask, fill_way=mlog.fill_way) + elif mlog.fill_way == Mlog.MLOG_23: + cal_mlog_count_from_mlogb(mlog) + m_outs_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) + caled_mtask = [] + for item in m_outs_qs.all(): + mtask = item.mtask + if mtask in caled_mtask: + continue + update_mtask(mtask, fill_way=mlog.fill_way) + caled_mtask.append(mtask) def cal_mlog_count_from_mlogb(mlog: Mlog): """ @@ -422,23 +450,6 @@ def cal_mlog_count_from_mlogb(mlog: Mlog): # 保存更新后的Mlog对象 mlog.save() -def cal_mtask_progress_from_mlog(mlog: Mlog): - """ - 更新mlog关联的任务进度(可线程中执行) - """ - if mlog.fill_way in [Mlog.MLOG_2, Mlog.MLOG_12] and mlog.mtask: - update_mtask(mlog.mtask, fill_way=mlog.fill_way) - elif mlog.fill_way == Mlog.MLOG_23: - cal_mlog_count_from_mlogb(mlog) - m_outs_qs = Mlogb.objects.filter(mlog=mlog, material_out__isnull=False) - caled_mtask = [] - for item in m_outs_qs.all(): - mtask = item.mtask - if mtask in caled_mtask: - continue - update_mtask(mtask, fill_way=mlog.fill_way) - caled_mtask.append(mtask) - def cal_material_count_from_mlog(mlog: Mlog): """ 更新mlog关联的物料数量(可单独执行) @@ -458,6 +469,7 @@ def cal_material_count_from_mlog(mlog: Mlog): def update_mtask(mtask: Mtask, fill_way: int = 10): + mtask = Mtask.objects.get(id=mtask.id) # 防止并发修改获取最新的mtask from apps.pm.models import Utask if fill_way == Mlog.MLOG_2: res = Mlog.objects.filter(mtask=mtask).exclude(submit_time=None).aggregate(sum_count_real=Sum( @@ -656,5 +668,4 @@ def mlog_audit_end(ticket: Ticket): now = timezone.now() ins = Mlog.objects.get(id=ticket.ticket_data['t_id']) mlog_submit(ins, ticket.create_by, now) - MyThread(target=cal_mtask_progress_from_mlog,args=(ins,)).start() - MyThread(target=cal_material_count_from_mlog,args=(ins,)).start() + diff --git a/apps/wpm/views.py b/apps/wpm/views.py index ea3006d6..98b634e6 100644 --- a/apps/wpm/views.py +++ b/apps/wpm/views.py @@ -1,6 +1,4 @@ from django.db import transaction -from django.db.models import Prefetch -from django.shortcuts import render from rest_framework.decorators import action from rest_framework.exceptions import ParseError from rest_framework.mixins import DestroyModelMixin, ListModelMixin, UpdateModelMixin, CreateModelMixin @@ -11,7 +9,6 @@ from django.utils import timezone from apps.system.models import User from apps.mtm.models import Material, Process -from apps.pm.models import Mtask from apps.utils.viewsets import CustomGenericViewSet, CustomModelViewSet from .filters import StLogFilter, SfLogFilter, WMaterialFilter, MlogFilter, HandoverFilter, MlogbFilter, BatchStFilter @@ -22,10 +19,9 @@ from .serializers import (SflogExpSerializer, SfLogSerializer, StLogSerializer, AttLogSerializer, OtherLogSerializer, MlogInitSerializer, MlogChangeSerializer, MlogbDetailSerializer, MlogbInSerializer, MlogbInUpdateSerializer, MlogbOutUpdateSerializer, FmlogSerializer, FmlogUpdateSerializer, BatchStSerializer) -from .services import mlog_submit, update_mtask, handover_submit, mlog_revert, cal_material_count_from_mlog, cal_mtask_progress_from_mlog -from apps.utils.thread import MyThread -from apps.monitor.services import create_auditlog, delete_auditlog +from .services import mlog_submit, handover_submit, mlog_revert from apps.wpm.services import mlog_submit_validate, generate_new_batch +from apps.wf.models import State # Create your views here. @@ -169,12 +165,18 @@ class MlogViewSet(CustomModelViewSet): def perform_destroy(self, instance): if instance.submit_time is not None: raise ParseError('日志已提交不可变动') + if instance.ticket and instance.ticket.state != State.STATE_TYPE_START: + raise ParseError('该日志存在审批!') # delete_auditlog(instance, instance.id) + if instance.ticket: + instance.ticket.delete() instance.delete() @transaction.atomic def perform_update(self, serializer): ins = serializer.instance + if ins.ticket and ins.ticket.state != State.STATE_TYPE_START: + raise ParseError('该日志在审批中不可修改!') if ins.submit_time is not None: raise ParseError('该日志已提交!') # val_old = MlogSerializer(instance=ins).data @@ -200,6 +202,8 @@ class MlogViewSet(CustomModelViewSet): 修改日志 """ ins = self.get_object() + if ins.ticket and ins.ticket.state != State.STATE_TYPE_START: + raise ParseError('该日志在审批中不可修改!') sr = MlogChangeSerializer(instance=ins, data=request.data) sr.is_valid(raise_exception=True) sr.save() @@ -225,8 +229,6 @@ class MlogViewSet(CustomModelViewSet): vdata_new = MlogSerializer(ins).data # create_auditlog('submit', ins, vdata_new, # vdata_old, now, self.request.user) - MyThread(target=cal_mtask_progress_from_mlog,args=(ins,)).start() - MyThread(target=cal_material_count_from_mlog,args=(ins,)).start() return Response(vdata_new) @action(methods=['post'], detail=True, perms_map={'post': 'mlog.submit'}, serializer_class=MlogRevertSerializer) @@ -236,6 +238,8 @@ class MlogViewSet(CustomModelViewSet): 撤回日志提交 """ ins: Mlog = self.get_object() + if ins.ticket: + raise ParseError('该日志存在审批!') user = request.user if ins.submit_time is None: raise ParseError('日志未提交不可撤销') @@ -246,8 +250,6 @@ class MlogViewSet(CustomModelViewSet): mlog_revert(ins, user, now) # create_auditlog('revert', ins, {}, {}, now, user, # request.data.get('change_reason', '')) - MyThread(target=cal_mtask_progress_from_mlog,args=(ins,)).start() - MyThread(target=cal_material_count_from_mlog,args=(ins,)).start() return Response(MlogSerializer(instance=ins).data) @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=MlogRelatedSerializer)