首件检查
This commit is contained in:
parent
7a1df98575
commit
65a4ab8934
|
@ -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',
|
||||
),
|
||||
]
|
|
@ -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):
|
||||
"""
|
||||
子计划生产进度统计表/物料消耗
|
||||
|
|
|
@ -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()
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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),
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue