首件检查

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_WORKING, '生产中'),
(SUBPLAN_STATE_DONE, '已完成'), (SUBPLAN_STATE_DONE, '已完成'),
) )
number = models.CharField('子计划编号', max_length=50, unique=True, null=True, blank=True) 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') 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') 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) end_date_real = models.DateField('实际完工日期', null=True, blank=True)
is_picked = models.BooleanField('是否已领料', default=False) is_picked = models.BooleanField('是否已领料', default=False)
# wproducts = models.JSONField('半成品表', default=list, blank=True) first_test_state = models.IntegerField('首件状态', default=SUBPLAN_STATE_PLANING)
is_testok = models.BooleanField('首件是否合格', null=True, blank=True) first_test = models.ForeignKey('qm.testrecord', on_delete=models.CASCADE, 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')
leader_1 = models.ForeignKey(User, on_delete=models.CASCADE, leader_1 = models.ForeignKey(User, on_delete=models.CASCADE,
verbose_name="工序负责人", null=True, blank=True, related_name='first_leader_1') verbose_name="工序负责人", null=True, blank=True, related_name='first_leader_1')
leader_2 = models.ForeignKey(User, on_delete=models.CASCADE, leader_2 = models.ForeignKey(User, on_delete=models.CASCADE,
@ -109,16 +107,6 @@ class SubProductionPlan(CommonAModel):
verbose_name = '子生产计划' verbose_name = '子生产计划'
verbose_name_plural = 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): class SubProductionProgress(BaseModel):
""" """
子计划生产进度统计表/物料消耗 子计划生产进度统计表/物料消耗

View File

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

View File

@ -5,23 +5,27 @@ from rest_framework import serializers
from rest_framework.views import APIView from rest_framework.views import APIView
from apps.em.models import Equipment from apps.em.models import Equipment
from apps.em.serializers import EquipmentSimpleSerializer from apps.em.serializers import EquipmentSimpleSerializer
from apps.hrm.services import HRMService
from apps.inm.models import MaterialBatch from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer 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.pm.filters import PlanFilterSet, SubproductionProgressFilterSet
from apps.qm.models import TestRecord, TestRecordItem
from apps.system.mixins import CreateUpdateModelAMixin 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 rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan
from rest_framework.viewsets import GenericViewSet, ModelViewSet from rest_framework.viewsets import GenericViewSet, ModelViewSet
from django.shortcuts import render from django.shortcuts import render
from apps.sam.models import Order 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.response import Response
from rest_framework.decorators import action from rest_framework.decorators import action
from django.db.models import F from django.db.models import F
from utils.tools import ranstr from utils.tools import ranstr
from django.db import transaction from django.db import transaction
from rest_framework import status
from django.utils import timezone
# Create your views here. # Create your views here.
def updateOrderPlanedCount(order): def updateOrderPlanedCount(order):
@ -145,7 +149,9 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
子生产计划-列表/修改 子生产计划-列表/修改
""" """
perms_map = {'get': '*', 'put':'subplan_update'} 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 = [] search_fields = []
serializer_class = SubProductionPlanListSerializer serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan', 'process', 'state', 'product', 'workshop'] filterset_fields = ['production_plan', 'process', 'state', 'product', 'workshop']
@ -229,20 +235,64 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
have = MaterialBatchSerializer(instance=objs, many=True).data have = MaterialBatchSerializer(instance=objs, many=True).data
return Response({'need':need, 'have':have}) 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 @transaction.atomic
def first_test_init(self, request, pk=None): def first_test_init(self, request, pk=None):
""" """
获取首件检查表 首件检查表初始化
""" """
obj = self.get_object() obj = self.get_object()
if obj.is_testok is None: if obj.first_test is None:
rdata = request.data rdata = request.data
serializer = self.get_serializer(data=rdata) serializer = self.get_serializer(data=rdata)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
form = serializer.validated_data.get('form') form = serializer.validated_data.get('form')
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('首件检查已存在')
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 = 20
TEST_PROCESS_RE = 30 TEST_PROCESS_RE = 30
TEST_COMB = 36 TEST_COMB = 36
@ -55,7 +56,8 @@ class TestRecord(CommonADModel):
(TEST_PROCESS, '工序检验'), (TEST_PROCESS, '工序检验'),
(TEST_PROCESS_RE, '工序复检'), (TEST_PROCESS_RE, '工序复检'),
(TEST_COMB, '夹层检验'), (TEST_COMB, '夹层检验'),
(TEST_FINAL, '成品检验') (TEST_FINAL, '成品检验'),
(TEST_FIRST, '首件检验')
) )
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE) form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
type = models.PositiveSmallIntegerField(choices=type_choice, default=TEST_PROCESS) type = models.PositiveSmallIntegerField(choices=type_choice, default=TEST_PROCESS)

View File

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

View File

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

View File

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