首件检查

This commit is contained in:
caoqianming 2022-02-21 10:40:58 +08:00
parent 7a1df98575
commit 65a4ab8934
9 changed files with 137 additions and 48 deletions

View File

@ -0,0 +1,40 @@
# Generated by Django 3.2.9 on 2022-02-21 02:27
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('qm', '0025_alter_testrecord_type'),
('pm', '0026_auto_20220218_1636'),
]
operations = [
migrations.RemoveField(
model_name='subproductionplan',
name='form',
),
migrations.RemoveField(
model_name='subproductionplan',
name='is_testok',
),
migrations.RemoveField(
model_name='subproductionplan',
name='tester',
),
migrations.AddField(
model_name='subproductionplan',
name='first_test',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testrecord'),
),
migrations.AddField(
model_name='subproductionplan',
name='first_test_state',
field=models.IntegerField(default=10, verbose_name='首件状态'),
),
migrations.DeleteModel(
name='FirstItem',
),
]

View File

@ -69,6 +69,7 @@ class SubProductionPlan(CommonAModel):
(SUBPLAN_STATE_WORKING, '生产中'),
(SUBPLAN_STATE_DONE, '已完成'),
)
number = models.CharField('子计划编号', max_length=50, unique=True, null=True, blank=True)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE, related_name='subplan_plan')
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subplan_subprod')
@ -91,11 +92,8 @@ class SubProductionPlan(CommonAModel):
end_date_real = models.DateField('实际完工日期', null=True, blank=True)
is_picked = models.BooleanField('是否已领料', default=False)
# wproducts = models.JSONField('半成品表', default=list, blank=True)
is_testok = models.BooleanField('首件是否合格', null=True, blank=True)
form = models.ForeignKey(RecordForm, verbose_name='首件检查表', on_delete=models.CASCADE, null=True, blank=True)
tester = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="首件检查员", null=True, blank=True, related_name='first_tester')
first_test_state = models.IntegerField('首件状态', default=SUBPLAN_STATE_PLANING)
first_test = models.ForeignKey('qm.testrecord', on_delete=models.CASCADE, null=True, blank=True)
leader_1 = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="工序负责人", null=True, blank=True, related_name='first_leader_1')
leader_2 = models.ForeignKey(User, on_delete=models.CASCADE,
@ -109,16 +107,6 @@ class SubProductionPlan(CommonAModel):
verbose_name = '子生产计划'
verbose_name_plural = verbose_name
class FirstItem(BaseModel):
"""
首件确认表记录条目
"""
form_field = models.ForeignKey(RecordFormField, verbose_name='关联自定义表格字段', on_delete=models.CASCADE)
field_value = models.JSONField('录入值', null=True, blank=True)
is_hidden = models.BooleanField('是否隐藏', default=False)
is_testok = models.BooleanField('是否合格', null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE, related_name='item_test_record')
class SubProductionProgress(BaseModel):
"""
子计划生产进度统计表/物料消耗

View File

@ -33,12 +33,15 @@ class ResourceConvertListSerializer(serializers.ListSerializer):
class ResourceCalListSerializer(serializers.ListSerializer):
child = ResourceCalSerializer()
class SubProductionPlanListSerializer(serializers.ModelSerializer):
class SubProductionPlanListSerializer(DynamicFieldsSerializerMixin, serializers.ModelSerializer):
workshop_ = OrganizationSimpleSerializer(source='workshop', read_only=True)
process_ = ProcessSimpleSerializer(source='process', read_only=True)
subproduction_ = SubProductionSimpleSerializer(source='subproduction', read_only=True)
product_ = MaterialSimpleSerializer(source='product', read_only=True)
plan_product_ = serializers.SerializerMethodField()
leader_1_ = UserSimpleSerializer(source='leader_1', read_only=True)
leader_2_ = UserSimpleSerializer(source='leader_2', read_only=True)
leader_3_ = UserSimpleSerializer(source='leader_3', read_only=True)
class Meta:
model=SubProductionPlan
fields = '__all__'
@ -81,20 +84,7 @@ class SubProductionProgressSerializer(serializers.ModelSerializer):
class FirstTestInitSerializer(serializers.Serializer):
form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=True)
class FirstTestDetailSerializer(serializers.ModelSerializer):
tester_ = UserSimpleSerializer(source='tester', read_only=True)
leader_1_ = UserSimpleSerializer(source='leader_1', read_only=True)
leader_2_ = UserSimpleSerializer(source='leader_2', read_only=True)
leader_3_ = UserSimpleSerializer(source='leader_3', read_only=True)
form_ = RecordFormSimpleSerializer(source='form', read_only=True)
# record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True)
record_data = serializers.SerializerMethodField()
class Meta:
model = SubProductionPlan
fields = ['id', 'form', 'form_', 'is_testok', 'remark', 'first_sign_time'
'tester', 'tester_', 'leader_1', 'leader_1_', 'leader_2',
'leader_2_', 'leader_3', 'leader_3_']
def get_record_data(self, obj):
return None
class FirstTestAuditSerializer(serializers.Serializer):
leader = serializers.CharField()
base64 = serializers.CharField()

View File

@ -5,23 +5,27 @@ from rest_framework import serializers
from rest_framework.views import APIView
from apps.em.models import Equipment
from apps.em.serializers import EquipmentSimpleSerializer
from apps.hrm.services import HRMService
from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import Material, Step, SubProduction, SubprodctionMaterial
from apps.mtm.models import Material, RecordFormField, Step, SubProduction, SubprodctionMaterial
from apps.pm.filters import PlanFilterSet, SubproductionProgressFilterSet
from apps.qm.models import TestRecord, TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import FirstTestInitSerializer, GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, ResourceConvertListSerializer, ResourceConvertSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from apps.pm.serializers import FirstTestAuditSerializer, FirstTestInitSerializer, GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, ResourceConvertListSerializer, ResourceConvertSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from django.shortcuts import render
from apps.sam.models import Order
from rest_framework.exceptions import APIException, ParseError
from rest_framework.exceptions import APIException, ParseError, ValidationError
from rest_framework.response import Response
from rest_framework.decorators import action
from django.db.models import F
from utils.tools import ranstr
from django.db import transaction
from rest_framework import status
from django.utils import timezone
# Create your views here.
def updateOrderPlanedCount(order):
@ -145,7 +149,9 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
子生产计划-列表/修改
"""
perms_map = {'get': '*', 'put':'subplan_update'}
queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'product', 'production_plan__product')
queryset = SubProductionPlan.objects.select_related('process',
'workshop', 'subproduction', 'product',
'production_plan__product', 'leader_1', 'leader_2', 'leader_3')
search_fields = []
serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan', 'process', 'state', 'product', 'workshop']
@ -229,20 +235,64 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
have = MaterialBatchSerializer(instance=objs, many=True).data
return Response({'need':need, 'have':have})
@action(methods=['put'], detail=True, perms_map={'post':'first_test'}, serializer_class=FirstTestInitSerializer)
@action(methods=['post'], detail=True, perms_map={'post':'first_test'}, serializer_class=FirstTestInitSerializer)
@transaction.atomic
def first_test_init(self, request, pk=None):
"""
获取首件检查表
首件检查表初始化
"""
obj = self.get_object()
if obj.is_testok is None:
if obj.first_test is None:
rdata = request.data
serializer = self.get_serializer(data=rdata)
serializer.is_valid(raise_exception=True)
form = serializer.validated_data.get('form')
raise APIException('已经过首件确认')
savedict = dict(
create_by=request.user,
subproduction_plan=obj,
type = TestRecord.TEST_FIRST,
form=form)
tr = TestRecord.objects.create(**savedict)
for i in RecordFormField.objects.filter(form=form, is_deleted=False):
tri = TestRecordItem()
tri.test_record = tr
tri.form_field = i
tri.is_hidden = i.is_hidden
tri.create_by = request.user
tri.save()
return Response()
raise APIException('首件检查已存在')
@action(methods=['post'], detail=True, perms_map={'post':'first_test_audit'}, serializer_class=FirstTestAuditSerializer)
@transaction.atomic
def first_audit(self, request, pk=None):
obj = self.get_object()
if obj.leader_1 and obj.leader_2 and obj.leader_3:
raise ValidationError('首件确认已完成')
if obj.first_test is None:
raise ValidationError('未进行首件检查')
if not obj.first_test.is_submited:
raise ValidationError('首件检查未提交')
if not obj.first_test.is_testok:
raise ValidationError('首件检查不合格')
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
user, msg = HRMService.face_compare_from_base64(vdata.get('base64'))
if user:
le = vdata.get('leader')
if le not in ['leader_1', 'leader_2', 'leader_3']:
return Response('审核人有误', status=status.HTTP_400_BAD_REQUEST)
if vdata.get('leader') == 'leader_1':
obj.leader_1 = user
elif vdata.get('leader') == 'leader_2':
obj.leader_2 = user
else:
obj.leader_3 = user
obj.first_sign_time = timezone.now()
obj.save()
return Response()
return Response(msg, status=status.HTTP_400_BAD_REQUEST)

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.9 on 2022-02-21 02:27
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0024_rename_is_midtesing_testrecord_is_midtesting'),
]
operations = [
migrations.AlterField(
model_name='testrecord',
name='type',
field=models.PositiveSmallIntegerField(choices=[(20, '工序检验'), (30, '工序复检'), (36, '夹层检验'), (40, '成品检验'), (10, '首件检验')], default=20),
),
]

View File

@ -47,6 +47,7 @@ class TestRecord(CommonADModel):
"""
检验记录
"""
TEST_FIRST = 10
TEST_PROCESS = 20
TEST_PROCESS_RE = 30
TEST_COMB = 36
@ -55,7 +56,8 @@ class TestRecord(CommonADModel):
(TEST_PROCESS, '工序检验'),
(TEST_PROCESS_RE, '工序复检'),
(TEST_COMB, '夹层检验'),
(TEST_FINAL, '成品检验')
(TEST_FINAL, '成品检验'),
(TEST_FIRST, '首件检验')
)
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
type = models.PositiveSmallIntegerField(choices=type_choice, default=TEST_PROCESS)

View File

@ -93,7 +93,8 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De
with transaction.atomic():
obj.is_submited=True
obj.save()
WpmService.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算
if obj.wproduct:
WpmService.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算
return Response()
# def create(self, request, *args, **kwargs):

View File

@ -90,7 +90,7 @@ class WorkflowViewSet(CreateUpdateModelAMixin, ModelViewSet):
class StateViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'get':'*', 'post':'workflow_update',
'put':'workflow_update', 'delete':'workflow_delete'}
'put':'workflow_update', 'delete':'workflow_update'}
queryset = State.objects.all()
serializer_class = StateSerializer
search_fields = ['name']
@ -99,7 +99,7 @@ class StateViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, Destr
class TransitionViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'get':'*', 'post':'workflow_update',
'put':'workflow_update', 'delete':'workflow_delete'}
'put':'workflow_update', 'delete':'workflow_update'}
queryset = Transition.objects.all()
serializer_class = TransitionSerializer
search_fields = ['name']
@ -108,7 +108,7 @@ class TransitionViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin,
class CustomFieldViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet):
perms_map = {'get':'*', 'post':'workflow_update',
'put':'workflow_update', 'delete':'workflow_delete'}
'put':'workflow_update', 'delete':'workflow_update'}
queryset = CustomField.objects.all()
serializer_class = CustomFieldSerializer
search_fields = ['field_name']

View File

@ -62,8 +62,8 @@ class FitJSONRenderer(JSONRenderer):
if isinstance(data, list):
data = data[0]
response_body.msg = prefix + ":" + str(data) # 取一部分放入msg,方便前端alert
response_body.msg = prefix + str(data) # 取一部分放入msg,方便前端alert
else:
response_body.data = data
renderer_context.get("response").status_code = 200 # 统一成200响应, 可用body里code区分业务异常
return super(FitJSONRenderer, self).render(response_body.dict, accepted_media_type, renderer_context)
return super(FitJSONRenderer, self).render(response_body.dict, accepted_media_type, renderer_context)