Merge branch 'master' of https://e.coding.net/ctcdevteam/ehs/ehs_server
This commit is contained in:
commit
c08dff56bf
|
@ -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='工序生产类型'),
|
||||
),
|
||||
]
|
|
@ -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='切分数量'),
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -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):
|
||||
"""
|
||||
检测项目
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
@ -114,3 +116,5 @@ 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)
|
||||
if ins.batch:
|
||||
MyThread(target=get_alldata_with_batch_and_store, args=(ins.batch,)).start()
|
|
@ -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()),
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -226,6 +226,18 @@ class PermissionSerializer(CustomModelSerializer):
|
|||
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):
|
||||
"""
|
||||
|
|
|
@ -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]))
|
||||
|
@ -544,6 +545,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):
|
||||
"""
|
||||
|
|
|
@ -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存取(包括功能和数据权限)
|
||||
|
|
|
@ -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
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue