From 8c356308406e4213c332a57d1edf965641c424dc Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sat, 29 Jan 2022 15:25:17 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B7=A5=E5=BA=8F=E4=B8=AD=E6=A3=80=E9=AA=8C?= =?UTF-8?q?=E5=9F=BA=E6=9C=AC=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/develop/views.py | 6 +- .../mtm/migrations/0045_usedstep_need_test.py | 18 ++ hb_server/apps/mtm/models.py | 1 + hb_server/apps/pm/filters.py | 6 +- hb_server/apps/pm/views.py | 3 +- .../qm/migrations/0023_auto_20220129_1512.py | 36 +++ ...e_is_midtesing_testrecord_is_midtesting.py | 18 ++ hb_server/apps/qm/models.py | 3 +- hb_server/apps/qm/serializers.py | 6 +- hb_server/apps/qm/views.py | 12 +- hb_server/apps/wpm/filters.py | 6 +- .../wpm/migrations/0053_auto_20220129_1512.py | 65 ++++ hb_server/apps/wpm/models.py | 24 +- hb_server/apps/wpm/services.py | 18 +- hb_server/apps/wpm/signals.py | 8 +- hb_server/apps/wpm/urls.py | 4 +- hb_server/apps/wpm/views.py | 298 ++++-------------- 17 files changed, 247 insertions(+), 285 deletions(-) create mode 100644 hb_server/apps/mtm/migrations/0045_usedstep_need_test.py create mode 100644 hb_server/apps/qm/migrations/0023_auto_20220129_1512.py create mode 100644 hb_server/apps/qm/migrations/0024_rename_is_midtesing_testrecord_is_midtesting.py create mode 100644 hb_server/apps/wpm/migrations/0053_auto_20220129_1512.py diff --git a/hb_server/apps/develop/views.py b/hb_server/apps/develop/views.py index 1e84384..2412742 100644 --- a/hb_server/apps/develop/views.py +++ b/hb_server/apps/develop/views.py @@ -10,7 +10,7 @@ from apps.pm.models import ProductionPlan, SubProductionPlan from apps.sam.models import Order from apps.wf.models import Ticket from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow -from apps.wpm.services import WpmServies +from apps.wpm.services import WpmService from apps.em.tasks import update_equip_state_by_next_check_date # Create your views here. @@ -46,7 +46,7 @@ class UpdateCuttingView(APIView): i.coperation = op i.save() WproductFlow.objects.filter(wproduct=i).update(coperation=op) - WpmServies.update_cutting_list_with_operation(op) + WpmService.update_cutting_list_with_operation(op) return Response() from apps.qm.models import TestRecord @@ -90,7 +90,7 @@ class UpdateSpg(APIView): 冷加工重新计算合格率 """ for i in SubProductionPlan.objects.filter(subproduction__process__id=1): - WpmServies.update_subproduction_progress_main(sp=i) + WpmService.update_subproduction_progress_main(sp=i) return Response() diff --git a/hb_server/apps/mtm/migrations/0045_usedstep_need_test.py b/hb_server/apps/mtm/migrations/0045_usedstep_need_test.py new file mode 100644 index 0000000..11b7fff --- /dev/null +++ b/hb_server/apps/mtm/migrations/0045_usedstep_need_test.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2022-01-29 07:12 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0044_subproduction_need_combtest'), + ] + + operations = [ + migrations.AddField( + model_name='usedstep', + name='need_test', + field=models.BooleanField(default=False, verbose_name='工序内检验'), + ), + ] diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index 4afb8b5..f8ccc83 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -242,6 +242,7 @@ class UsedStep(CommonADModel): 涉及的生产子工序 """ step = models.ForeignKey(Step, verbose_name='子工序', on_delete=models.CASCADE, related_name='usedstep') + need_test = models.BooleanField('工序内检验', default=False) remark = models.TextField('生产备注', null=True, blank=True) subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='usedstep_subproduction') diff --git a/hb_server/apps/pm/filters.py b/hb_server/apps/pm/filters.py index aa9c6da..a53c29d 100644 --- a/hb_server/apps/pm/filters.py +++ b/hb_server/apps/pm/filters.py @@ -3,7 +3,7 @@ from apps.mtm.models import Material, Step from apps.pm.models import ProductionPlan, SubProductionProgress from apps.wpm.models import Operation, WProduct from datetime import * -from apps.wpm.services import WpmServies +from apps.wpm.services import WpmService from django.db.models import F from utils.mixins import DynamicFieldsFilterMixin @@ -52,9 +52,9 @@ class SubproductionProgressFilterSet(filters.FilterSet): wproducts = WProduct.objects.filter(ow_wproduct__operation=value) step = operation.step if wproducts.exists(): - subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts) + subplans = WpmService.get_subplans_queryset_from_wproducts(wproducts) else: - subplans = WpmServies.get_subplans_queyset_from_step(step) + subplans = WpmService.get_subplans_queyset_from_step(step) queryset = queryset.filter(subproduction_plan__in=subplans) if step.type == Step.STEP_TYPE_NOM: queryset = queryset.exclude(material__type__in =[Material.MA_TYPE_HALFGOOD, Material.MA_TYPE_GOOD]) diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py index 0fea0a7..449cb2d 100644 --- a/hb_server/apps/pm/views.py +++ b/hb_server/apps/pm/views.py @@ -89,7 +89,8 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number') for index, i in enumerate(subps): steps = Step.objects.filter(usedstep__subproduction=i, usedstep__subproduction__is_deleted=False, - usedstep__is_deleted=False, is_deleted=False).values('id', 'number', 'name', 'usedstep__remark') + usedstep__is_deleted=False, is_deleted=False + ).values('id', 'number', 'name', 'usedstep__remark', need_test=F('usedstep__need_test')) instance = SubProductionPlan.objects.create(production_plan=production_plan, subproduction=i, start_date=production_plan.start_date, end_date=production_plan.end_date, workshop=i.process.workshop, process=i.process, create_by=request.user, diff --git a/hb_server/apps/qm/migrations/0023_auto_20220129_1512.py b/hb_server/apps/qm/migrations/0023_auto_20220129_1512.py new file mode 100644 index 0000000..912b50e --- /dev/null +++ b/hb_server/apps/qm/migrations/0023_auto_20220129_1512.py @@ -0,0 +1,36 @@ +# Generated by Django 3.2.9 on 2022-01-29 07:12 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('qm', '0022_auto_20211216_1401'), + ] + + operations = [ + migrations.AddField( + model_name='testrecord', + name='is_midtesing', + field=models.BooleanField(default=False, verbose_name='是否子工序检验中'), + ), + migrations.AddField( + model_name='testrecorditem', + name='create_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testrecorditem_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人'), + ), + migrations.AddField( + model_name='testrecorditem', + name='update_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testrecorditem_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'), + ), + migrations.AlterField( + model_name='testrecord', + name='type', + field=models.PositiveSmallIntegerField(choices=[(20, '工序检验'), (30, '工序复检'), (36, '夹层检验'), (40, '成品检验')], default=20), + ), + ] diff --git a/hb_server/apps/qm/migrations/0024_rename_is_midtesing_testrecord_is_midtesting.py b/hb_server/apps/qm/migrations/0024_rename_is_midtesing_testrecord_is_midtesting.py new file mode 100644 index 0000000..720045d --- /dev/null +++ b/hb_server/apps/qm/migrations/0024_rename_is_midtesing_testrecord_is_midtesting.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2022-01-29 07:24 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0023_auto_20220129_1512'), + ] + + operations = [ + migrations.RenameField( + model_name='testrecord', + old_name='is_midtesing', + new_name='is_midtesting', + ), + ] diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index c3db665..db776de 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -47,13 +47,11 @@ class TestRecord(CommonADModel): """ 检验记录 """ - TEST_STEP = 10 TEST_PROCESS = 20 TEST_PROCESS_RE = 30 TEST_COMB = 36 TEST_FINAL = 40 type_choice = ( - (TEST_STEP, '子工序检验'), (TEST_PROCESS, '工序检验'), (TEST_PROCESS_RE, '工序复检'), (TEST_COMB, '夹层检验'), @@ -70,6 +68,7 @@ class TestRecord(CommonADModel): fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True) origin_test = models.ForeignKey('self', verbose_name='原检验记录', on_delete=models.CASCADE, null=True, blank=True) is_submited = models.BooleanField('是否提交', default=False) + is_midtesting = models.BooleanField('是否子工序检验中', default=False) remark = models.TextField('备注', default='') diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index ecfc2d3..fd64cd6 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -135,7 +135,7 @@ class TestRecordUpdateSerializer(serializers.ModelSerializer): if i['field_value'] != tri.field_value: tri.field_value = i['field_value'] tri.update_by = update_by - tri.is_testok = i['is_testok'] - tri.is_hidden = i['is_hidden'] - tri.save() + tri.is_testok = i['is_testok'] + tri.is_hidden = i['is_hidden'] + tri.save() return instance diff --git a/hb_server/apps/qm/views.py b/hb_server/apps/qm/views.py index 247e6d6..7cb1f40 100644 --- a/hb_server/apps/qm/views.py +++ b/hb_server/apps/qm/views.py @@ -12,7 +12,7 @@ from django.db import transaction from rest_framework.decorators import action from apps.wpm.models import WProduct -from apps.wpm.services import WpmServies +from apps.wpm.services import WpmService # Create your views here. class StandardViewSet(CreateUpdateModelAMixin, ModelViewSet): """ @@ -69,7 +69,7 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De def update(self, request, *args, **kwargs): obj = self.get_object() - if obj.is_submited: + if obj.is_submited and obj.is_midtesting is False: raise exceptions.APIException('该记录已提交不可编辑') return super().update(request, *args, **kwargs) @@ -77,20 +77,22 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De obj = self.get_object() if obj.is_submited: raise exceptions.APIException('该记录已提交不可删除') - WpmServies.add_wproduct_flow_log(obj.wproduct, 'test_delete') + WpmService.add_wproduct_flow_log(obj.wproduct, 'test_delete') return super().destroy(request, *args, **kwargs) @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=TestRecordUpdateSerializer) def submit(self, request, pk=None): obj = self.get_object() + if obj.is_submited and obj.is_midtesting is False: + raise exceptions.APIException('该记录已提交') # 校验是否有未填项目 - if obj.type != TestRecord.TEST_PROCESS_RE: + if obj.type != TestRecord.TEST_PROCESS_RE and obj.is_midtesting is False: if TestRecordItem.objects.filter(field_value__isnull=True, is_hidden=False, test_record=obj).exists(): raise exceptions.APIException('存在未填写项目') with transaction.atomic(): obj.is_submited=True obj.save() - WpmServies.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算 + WpmService.update_wproduct_by_test(obj, request.user) # 这里已经做了日志记录和进度计算 return Response() # def create(self, request, *args, **kwargs): diff --git a/hb_server/apps/wpm/filters.py b/hb_server/apps/wpm/filters.py index 5cfb6ea..2798e98 100644 --- a/hb_server/apps/wpm/filters.py +++ b/hb_server/apps/wpm/filters.py @@ -1,7 +1,7 @@ from django_filters import rest_framework as filters from apps.mtm.models import Material, Step -from apps.wpm.services import WpmServies +from apps.wpm.services import WpmService from utils.mixins import DynamicFieldsFilterMixin from .models import Operation, OperationMaterial, OperationRecord, WMaterial, WProduct @@ -20,10 +20,10 @@ class WMaterialFilterSet(filters.FilterSet): wproducts = WProduct.objects.filter(ow_wproduct__operation=value) step = operation.step if wproducts.exists(): - subplans = WpmServies.get_subplans_queryset_from_wproducts( + subplans = WpmService.get_subplans_queryset_from_wproducts( wproducts) else: - subplans = WpmServies.get_subplans_queyset_from_step(step) + subplans = WpmService.get_subplans_queyset_from_step(step) queryset = queryset.filter(subproduction_plan__in=subplans).exclude( material__type=Material.MA_TYPE_HALFGOOD) return queryset diff --git a/hb_server/apps/wpm/migrations/0053_auto_20220129_1512.py b/hb_server/apps/wpm/migrations/0053_auto_20220129_1512.py new file mode 100644 index 0000000..21d27fe --- /dev/null +++ b/hb_server/apps/wpm/migrations/0053_auto_20220129_1512.py @@ -0,0 +1,65 @@ +# Generated by Django 3.2.9 on 2022-01-29 07:12 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0045_usedstep_need_test'), + ('wpm', '0052_auto_20220125_1116'), + ] + + operations = [ + migrations.AddField( + model_name='wproduct', + name='material_check', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_material_check', to='mtm.material', verbose_name='按物料状态检查'), + ), + migrations.AddField( + model_name='wproductflow', + name='material_check', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_material_check', to='mtm.material', verbose_name='按物料状态检查'), + ), + migrations.AlterField( + model_name='wproduct', + name='child', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_child', to='wpm.wproduct'), + ), + migrations.AlterField( + model_name='wproduct', + name='material', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wp_material', to='mtm.material', verbose_name='所属物料状态'), + ), + migrations.AlterField( + model_name='wproduct', + name='pre_step', + field=models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_pre_step', to='mtm.step', verbose_name='已执行到'), + ), + migrations.AlterField( + model_name='wproduct', + name='step', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wp_step', to='mtm.step', verbose_name='所在步骤'), + ), + migrations.AlterField( + model_name='wproductflow', + name='child', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_child', to='wpm.wproductflow'), + ), + migrations.AlterField( + model_name='wproductflow', + name='material', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wpf_material', to='mtm.material', verbose_name='所属物料状态'), + ), + migrations.AlterField( + model_name='wproductflow', + name='pre_step', + field=models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_pre_step', to='mtm.step', verbose_name='已执行到'), + ), + migrations.AlterField( + model_name='wproductflow', + name='step', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='wpf_step', to='mtm.step', verbose_name='所在步骤'), + ), + ] diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 571960e..997e65c 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -1,4 +1,5 @@ import re + from rest_framework import exceptions from django.db import models from django.db.models.base import Model @@ -88,16 +89,20 @@ class WProduct(CommonAModel): number = models.CharField( '物品编号', unique=True, null=True, blank=True, max_length=50) material = models.ForeignKey( - Material, verbose_name='所属物料状态', on_delete=models.CASCADE) + Material, verbose_name='所属物料状态', on_delete=models.CASCADE, + related_name='wp_material') + material_check = models.ForeignKey( + Material, verbose_name='按物料状态检查', on_delete=models.CASCADE, + null=True, blank=True, related_name='wp_material_check') pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, - on_delete=models.CASCADE, related_name='w_pre_step') + on_delete=models.CASCADE, related_name='wp_pre_step') step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, - related_name='w_step') + related_name='wp_step') act_state = models.IntegerField( '进行状态', default=0, choices=act_state_choices) is_hidden = models.BooleanField('是否隐藏', default=False) child = models.ForeignKey('self', blank=True, null=True, - on_delete=models.CASCADE, related_name='wproduct_child') + on_delete=models.CASCADE, related_name='wp_child') remark = models.CharField('备注', max_length=200, null=True, blank=True) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan') @@ -164,16 +169,19 @@ class WproductFlow(CommonAModel): WProduct, on_delete=models.CASCADE, verbose_name='关联产品', null=True, blank=True) number = models.CharField('物品编号', null=True, blank=True, max_length=50) material = models.ForeignKey( - Material, verbose_name='所属物料状态', on_delete=models.CASCADE) + Material, verbose_name='所属物料状态', on_delete=models.CASCADE, related_name='wpf_material') + material_check = models.ForeignKey( + Material, verbose_name='按物料状态检查', on_delete=models.CASCADE, + null=True, blank=True, related_name='wpf_material_check') pre_step = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, - on_delete=models.CASCADE, related_name='wl_pre_step') + on_delete=models.CASCADE, related_name='wpf_pre_step') step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, - related_name='wl_step') + related_name='wpf_step') act_state = models.IntegerField( '进行状态', default=0, choices=WProduct.act_state_choices) is_hidden = models.BooleanField('是否隐藏', default=False) child = models.ForeignKey('self', blank=True, null=True, - on_delete=models.CASCADE, related_name='wproduct_child') + on_delete=models.CASCADE, related_name='wpf_child') remark = models.CharField('备注', max_length=200, null=True, blank=True) subproduction_plan = models.ForeignKey( SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE) diff --git a/hb_server/apps/wpm/services.py b/hb_server/apps/wpm/services.py index d880f7f..c3ca066 100644 --- a/hb_server/apps/wpm/services.py +++ b/hb_server/apps/wpm/services.py @@ -9,19 +9,21 @@ from apps.system.models import User from apps.wf.models import State, TicketFlow, Transition from apps.wpm.models import Operation, OperationMaterial, WProduct, WproductFlow, WprouctTicket from utils.tools import ranstr -class WpmServies(object): +class WpmService(object): @classmethod def get_next_step(cls, subproduction_plan:SubProductionPlan, nowstep:Step): """ 获取下一步骤 """ - stepIds = [i['id'] for i in subproduction_plan.steps] + steps_list = subproduction_plan.steps + stepIds = [i['id'] for i in steps_list] pindex = stepIds.index(nowstep.id) + need_test = steps_list[pindex].get('need_test', False) if pindex + 1 < len(stepIds): - return Step.objects.get(pk=stepIds[pindex+1]), True + return Step.objects.get(pk=stepIds[pindex+1]), need_test else: - return nowstep, False + return nowstep, need_test @classmethod def get_subplans_queryset_from_wproducts(cls, wproducts:List): @@ -47,9 +49,15 @@ class WpmServies(object): """ is_testok = test.is_testok wproduct = test.wproduct + test_i = None if is_testok: if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检 wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT + + elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and \ + test.is_midtesing is True: + wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT + test_i = test elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD: # 成品检验 wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST @@ -97,7 +105,7 @@ class WpmServies(object): wproduct.update_by = user wproduct.update_time = timezone.now() - wproduct.test = None + wproduct.test = test_i wproduct.last_test_result = is_testok wproduct.save() # 添加日志 diff --git a/hb_server/apps/wpm/signals.py b/hb_server/apps/wpm/signals.py index 9b37b54..04455d7 100644 --- a/hb_server/apps/wpm/signals.py +++ b/hb_server/apps/wpm/signals.py @@ -8,7 +8,7 @@ from django.dispatch import receiver from rest_framework import exceptions from apps.wpm.models import WProduct, WproductFlow, WprouctTicket from apps.wpm.models import OperationWproduct -from apps.wpm.services import WpmServies +from apps.wpm.services import WpmService @receiver(post_save, sender=Ticket) @@ -34,7 +34,7 @@ def handleTicket(sender, instance, created, **kwargs): # 工单绑定半成品 wproduct.ticket = instance wproduct.save() - WpmServies.add_wproduct_flow_log(wproduct, 'ticket_create') + WpmService.add_wproduct_flow_log(wproduct, 'ticket_create') elif instance.act_state == Ticket.TICKET_ACT_STATE_FINISH: @@ -77,7 +77,7 @@ def handleTicket(sender, instance, created, **kwargs): wp.save() # 添加日志 - WpmServies.add_wproduct_flow_log(wp, 'ticket_finish') + WpmService.add_wproduct_flow_log(wp, 'ticket_finish') # 更新子计划合格进度 - WpmServies.update_subproduction_progress_main(sp=wp.subproduction_plan) + WpmService.update_subproduction_progress_main(sp=wp.subproduction_plan) diff --git a/hb_server/apps/wpm/urls.py b/hb_server/apps/wpm/urls.py index b617c02..40614fd 100644 --- a/hb_server/apps/wpm/urls.py +++ b/hb_server/apps/wpm/urls.py @@ -3,7 +3,7 @@ from rest_framework import urlpatterns from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.wpm.views import CuttingListViewSet, DoFormInit, DoFormSubmit, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet, WproductTicketViewSet +from apps.wpm.views import CuttingListViewSet, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet, WproductTicketViewSet router = DefaultRouter() router.register('wmaterial', WMaterialViewSet, basename='wmaterial') @@ -19,8 +19,6 @@ router.register('operation_tool', OperationMaterialToolViewSet, basename='operat router.register('subplan', WPlanViewSet, basename='wplan') router.register('cutting_list', CuttingListViewSet, basename='cutting_list') urlpatterns = [ - path('do/init/', DoFormInit.as_view()), - path('do/submit/', DoFormSubmit.as_view()), path('', include(router.urls)), ] diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 7696562..cf607ec 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -32,7 +32,7 @@ from apps.wpm.serializers import CuttingListSerializer, OperationEquipListSerial from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers -from apps.wpm.services import WpmServies +from apps.wpm.services import WpmService from django.utils import timezone from rest_framework import status from django.db.models import Count @@ -105,7 +105,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): m.update_by = request.user m.update_time = timezone.now() m.save() - WpmServies.add_wproduct_flow_log( + WpmService.add_wproduct_flow_log( instance=m, change_str='pick_half') pw = PickWproduct() pw.pick = pick @@ -151,7 +151,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): perms_map = {'*': '*'} queryset = WProduct.objects.select_related('step', 'material', 'subproduction_plan', 'warehouse', 'subproduction_plan__production_plan__order', - 'to_order').prefetch_related('wproduct_child') + 'to_order').prefetch_related('wp_child') serializer_class = WProductListSerializer filterset_class = WProductFilterSet search_fields = ['number'] @@ -188,7 +188,6 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST, WProduct.WPR_ACT_STATE_TOCOMBTEST]: raise exceptions.APIException('该产品当前状态不可检验') - savedict = dict( create_by=request.user, wproduct=wproduct, @@ -208,13 +207,16 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): savedict['type'] = TestRecord.TEST_FINAL elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOCOMBTEST: savedict['type'] = TestRecord.TEST_COMB + elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and\ + wproduct.step != wproduct.pre_step: # 如果是工序内检验 + savedict['is_midtesting'] = True tr = TestRecord.objects.create(**savedict) # 更新wproduct wproduct.test = tr wproduct.update_by = request.user wproduct.update_time = timezone.now() wproduct.save() - WpmServies.add_wproduct_flow_log(wproduct, 'test_init') + WpmService.add_wproduct_flow_log(wproduct, 'test_init') # 创建检验条目 for i in RecordFormField.objects.filter(form=form, is_deleted=False): tri = TestRecordItem() @@ -224,6 +226,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): tri.create_by = request.user tri.save() return Response(TestRecordDetailSerializer(instance=tr).data) + @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductPutInsSerializer) @transaction.atomic @@ -281,7 +284,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): i.update_by = request.user i.update_time = timezone.now() i.save() - WpmServies.add_wproduct_flow_log(i, 'putins') + WpmService.add_wproduct_flow_log(i, 'putins') return Response() @action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=WproductPutInSerializer) @@ -328,7 +331,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): wproduct.act_state = WProduct.WPR_ACT_STATE_INM wproduct.warehouse = warehouse wproduct.save() - WpmServies.add_wproduct_flow_log(wproduct, 'putin') + WpmService.add_wproduct_flow_log(wproduct, 'putin') return Response() @action(methods=['post'], detail=True, perms_map={'post': '*'}, serializer_class=ScrapSerializer) @@ -354,9 +357,9 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): obj.update_by = request.user obj.update_time = timezone.now() obj.save() - WpmServies.add_wproduct_flow_log(obj, 'scrap') + WpmService.add_wproduct_flow_log(obj, 'scrap') if obj.step.process.id == 1: # 如果是冷加工 - WpmServies.update_cutting_list_with_operation(obj.coperation) + WpmService.update_cutting_list_with_operation(obj.coperation) return Response() # @action(methods=['get'], detail=False, perms_map={'get':'*'}) @@ -411,14 +414,14 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): is_mtestok = request.data.get('is_mtestok') obj.is_mtestok = is_mtestok if is_mtestok: - WpmServies.update_plan_state_by_mtestok( + WpmService.update_plan_state_by_mtestok( obj.subproduction_plan.production_plan) obj.update_by = request.user obj.save() change_str = 'mtest_notok' if is_mtestok: change_str = 'mtest_ok' - WpmServies.add_wproduct_flow_log(instance=obj, change_str=change_str) + WpmService.add_wproduct_flow_log(instance=obj, change_str=change_str) return Response() @action(methods=['get'], detail=True, perms_map={'get': '*'}) @@ -461,7 +464,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): i.need_to_order = True i.update_by = request.user i.save() - WpmServies.add_wproduct_flow_log(i, change_str='need_to_order') + WpmService.add_wproduct_flow_log(i, change_str='need_to_order') return Response() @action(methods=['post'], detail=False, perms_map={'post': '*'}, serializer_class=WproductToOrderSerializer) @@ -486,7 +489,7 @@ class WProductViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): i.to_order = order i.update_by = request.user i.save() - WpmServies.add_wproduct_flow_log(i,change_str='to_order') + WpmService.add_wproduct_flow_log(i,change_str='to_order') return Response() class WproductTicketViewSet(ListModelMixin, GenericViewSet): @@ -544,7 +547,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd i.act_state = WProduct.WPR_ACT_STATE_DOWAIT i.update_by = request.user i.save() - WpmServies.add_wproduct_flow_log(i, 'operation_delete') + WpmService.add_wproduct_flow_log(i, 'operation_delete') self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) @@ -565,14 +568,14 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd # 创建操作所用半成品关联记录 if 'wproducts' in vdata: owps = [] - splans = WpmServies.get_subplans_queryset_from_wproducts( + splans = WpmService.get_subplans_queryset_from_wproducts( vdata['wproducts']) for wpd in vdata['wproducts']: wpd.operation = op wpd.act_state = WProduct.WPR_ACT_STATE_DOING wpd.update_by = request.user wpd.save() - WpmServies.add_wproduct_flow_log(wpd, 'operation_create') + WpmService.add_wproduct_flow_log(wpd, 'operation_create') owp = {} owp['operation'] = op owp['wproduct'] = wpd @@ -583,7 +586,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd owps.append(OperationWproduct(**owp)) OperationWproduct.objects.bulk_create(owps) else: - splans = WpmServies.get_subplans_queryset_from_wproducts( + splans = WpmService.get_subplans_queryset_from_wproducts( vdata['wproducts']) # 查询需要填写的自定义表格 forms = RecordForm.objects.filter( @@ -677,22 +680,30 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd wsp = i.subproduction_plan # 获取下一步子工序 - newstep, hasNext = WpmServies.get_next_step(wsp, step) + newstep, needTest = WpmService.get_next_step(wsp, step) wp.step = newstep wp.pre_step = step - if hasNext: - wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT - else: + + if step == newstep: wp.act_state = WProduct.WPR_ACT_STATE_TOTEST wp.material = wsp.product + if wp.test:# 如果有正在进行的工序中检验 + wp.test.is_midtesting = False + wp.test.save() + else: + wp.act_state = WProduct.WPR_ACT_STATE_DOWAIT + if needTest: + wp.act_state = WProduct.WPR_ACT_STATE_TOTEST + wp.material_check = wsp.product + wp.operation = None wp.update_by = request.user wp.save() - WpmServies.add_wproduct_flow_log(wp, 'operation_submit') + WpmService.add_wproduct_flow_log(wp, 'operation_submit') for i in ows.values('subproduction_plan').distinct(): # 更新进度 - WpmServies.update_subproduction_progress_main(sp=wsp) + WpmService.update_subproduction_progress_main(sp=wsp) elif step.type == Step.STEP_TYPE_DIV: # 更新物料产出情况 @@ -700,7 +711,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd raise exceptions.APIException('请选择物料产出') for i in omos: if i.subproduction_progress.is_main: - newstep, _ = WpmServies.get_next_step( + newstep, _ = WpmService.get_next_step( i.subproduction_plan, step) wpr = dict(material=i.material, step=newstep, act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='', @@ -709,33 +720,40 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd for x in range(i.count): ins = WProduct.objects.create(**wpr) # 添加日志 - WpmServies.add_wproduct_flow_log( + WpmService.add_wproduct_flow_log( ins, 'wproduct_create') # 更新进度 - WpmServies.update_subproduction_progress_main( + WpmService.update_subproduction_progress_main( sp=i.subproduction_plan) elif step.type == Step.STEP_TYPE_COMB: oms_w = omos.filter(subproduction_progress__is_main=True) if len(oms_w) == 1: oms_w = oms_w[0] # 校验单片数量是否正确, 暂时未写 - newstep, hasNext = WpmServies.get_next_step( + newstep, needTest = WpmService.get_next_step( oms_w.subproduction_plan, step) wproduct = WProduct() wproduct.material = oms_w.material wproduct.step = newstep wproduct.subproduction_plan = oms_w.subproduction_plan - if hasNext: - wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT - else: + if step == newstep: wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST - # 更新子计划进度 - WpmServies.update_subproduction_progress_main( - sp=oms_w.subproduction_plan) + if wproduct.test:# 如果有正在进行的工序中检验 + wproduct.test.is_midtesting = False + wproduct.test.save() + else: + wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT + if needTest: + wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST + wproduct.material_check = wproduct.product + + # 更新子计划进度 + WpmService.update_subproduction_progress_main( + sp=oms_w.subproduction_plan) wproduct.create_by = request.user wproduct.coperation = op wproduct.save() - WpmServies.add_wproduct_flow_log(wproduct, 'wproduct_create') + WpmService.add_wproduct_flow_log(wproduct, 'wproduct_create') # 隐藏原半成品 wps = WProduct.objects.filter(ow_wproduct__operation=op) wps.update(is_hidden=True, child=wproduct, @@ -747,7 +765,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd # 如果是冷加工 if step.process.id == 1: - WpmServies.update_cutting_list_with_operation(op=op) + WpmService.update_cutting_list_with_operation(op=op) return Response() @@ -971,213 +989,3 @@ class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyMode return Response() -class DoFormInit(CreateAPIView, GenericAPIView): - perms_map = {'*': '*'} - serializer_class = OperationInitSerializer - - def post(self, request, format=None): - """ - 调用操作表单 - """ - data = request.data - serializer = OperationInitSerializer(data=data) - serializer.is_valid(raise_exception=True) - vdata = serializer.validated_data - ret = {} - ret_0 = {} - ret_0['step'] = data['step'] - splans = [] - ret_0['input'] = [] - # ret_0['subproduction_plan'] = data['subproduction_plan'] - if 'wproducts' in data and data['wproducts']: - ret_0['wproducts'] = data['wproducts'] - splans = WProduct.objects.filter(id__in=data['wproducts']).values_list( - 'subproduction_plan', flat=True) - # 调出所属子计划现有物料 - ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter( - subproduction_plan__in=splans), many=True).data - else: - if 'subproduction_plan' in vdata: - splans = [vdata['subproduction_plan']] - else: - splans = SubProductionPlan.objects.filter(is_deleted=False, - subproduction__usedstep_subproduction__step=vdata[ - 'step'], - state=3) - ret_0['wproducts'] = [] - ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter( - subproduction_plan__in=splans), many=True).data - - for i in ret_0['input']: - i['count_input'] = 0 - # 需要输出的物料 - if ret_0['wproducts']: - # 排除主要产物, 因为已经放到半成品里了, 由半成品进行处理, 夹层可能需要特殊处理 - o_objs = SubProductionProgress.objects.filter( - subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT).exclude(is_main=True) - - else: - # 此时显示所有子计划需要输出的物料 - o_objs = SubProductionProgress.objects.filter( - subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) - ret_0['output'] = list(o_objs.values( - 'subproduction_plan', 'material', 'material__name', 'material__number')) - for i in ret_0['output']: - i['count_output'] = 0 - ret['forms'] = [] - ret_0['id'] = 0 - ret_0['name'] = '基本信息' - # 查询工具工装 - ret_0['tools'] = SubprodctionMaterialListSerializer( - instance=SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL, - subproduction__subplan_subprod__in=splans), many=True).data - # 查询技术文档 - ret_0['techdocs'] = TechDocListSerializer( - instance=TechDoc.objects.filter( - subproduction__subplan_subprod__in=splans, enabled=True) - .distinct(), many=True).data - - ret['forms'].append(ret_0) - forms = RecordForm.objects.filter( - step=vdata['step'], type=RecordForm.RF_TYPE_DO) - if forms.exists(): - ret['forms'].extend(RecordFormDetailSerializer( - instance=forms, many=True).data) - return Response(ret) - - -class DoFormSubmit(CreateAPIView, GenericAPIView): - perms_map = {'*': '*'} - serializer_class = OperationSubmitSerializer - - @transaction.atomic - def post(self, request, format=None): - """ - 提交操作表单 - """ - data = request.data - serializer = OperationSubmitSerializer( - data=data, context={'request': self.request}) - serializer.is_valid(raise_exception=True) - vdata = serializer.validated_data # 校验之后的数据 - - # 创建一个生产操作记录 - action_obj = Operation() - action_obj.step = vdata['step'] - action_obj.remark = vdata.get('remark', '') # 操作备注 - action_obj.create_by = request.user - action_obj.use_scrap = vdata.get('use_scrap', False) - action_obj.save() - - # 保存关联半成品 - if 'wproducts' in data and data['wproducts']: - owps = [] - for i in data['wproducts']: - owp = {} - owp['operation'] = action_obj - wp = WProduct.objects.get(pk=i) - owp['wproduct'] = wp - owp['number'] = wp.number - owp['material'] = wp.material - owp['subproduction_plan'] = wp.subproduction_plan - owps.append(OperationWproduct(**owp)) - OperationWproduct.objects.bulk_create(owps) - - # 保存物料消耗 - for i in vdata['input']: - if i['count_input']: # 如果有消耗 - i_wmat = i['id'] - OperationMaterial.objects.create(type=1, operation=action_obj, - wmaterial=i_wmat, count=i['count_input']) - # 更新车间物料 - i_wmat.count = i_wmat.count - i['count_input'] - i_wmat.save() - # 更新子计划物料消耗情况 - sp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan, - material=i_wmat.material) - sp.count_real = sp.count_real + i['count_input'] - sp.save() - - # 物料产出 - if 'output' in data and data['output']: - for i in vdata['output']: # 已经序列化好的数据 - ma = i['material'] - if i['subproduction_plan'].product == ma: # 如果是该计划主产物 - # 如果是切割 - # 获取下一步子工序 - if vdata['step'].type == Step.STEP_TYPE_DIV: - newstep, _ = WpmServies.get_next_step( - i['subproduction_plan'], vdata['step']) - wpr = dict(material=ma, step=newstep, - act_state=WProduct.WPR_ACT_STATE_DOWAIT, remark='', - subproduction_plan=i['subproduction_plan']) - for x in range(i['count_output']): - WProduct.objects.create(**wpr) - else: - # 更新操作产出物料表 - OperationMaterial.objects.create(type=2, operation=action_obj, - material=ma, count=i['count_output']) - # 更新车间物料表 - ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i['subproduction_plan'], - material=ma) - ins.count = ins.count + i['count_output'] - ins.save() - # 更新子计划进度表 - sp = SubProductionProgress.objects.get(subproduction_plan=i['subproduction_plan'], - material=ma) - sp.count_real = sp.count_real + i['count_input'] - sp.save() - - # 更新动态产品表 - if 'wproducts' in vdata and vdata['wproducts']: - if vdata['step'].type == Step.STEP_TYPE_COMB: - wproducts = vdata['wproducts'] - if 'suproduction_plan' in vdata: - wproducts.update(is_hidden=True) # 隐藏 - newstep, hasNext = WpmServies.get_next_step( - i['subproduction_plan'], vdata['step']) - wproduct = WProduct() - wproduct.material = vdata['subproduction_plan'].product - wproduct.step = newstep - wproduct.subproduction_plan = vdata['subproduction_plan'] - wproduct.parent = data['wproducts'] - if hasNext: - wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT - else: - wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST - wproduct.save() - else: - raise exceptions.APIException('请指定子计划') - else: - for wproduct in vdata['wproducts']: - # 获取下一步子工序 - newstep, hasNext = WpmServies.get_next_step( - wproduct.subproduction_plan, vdata['step']) - wproduct.step = newstep - wproduct.pre_step = vdata['step'] - if hasNext: - wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT - else: - wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST - wproduct.material = wproduct.subproduction_plan.product - wproduct.save() - - # 保存自定义表单结果 - for i in vdata['forms']: - wr = OperationRecord() - wr.form = i['form'] - wr.create_by = request.user - wr.operation = action_obj - wr.save() - wrds = [] - for m in i['record_data']: # 保存记录详情 - form_field = m['form_field'] - m['field_name'] = form_field.field_name - m['field_key'] = form_field.field_key - m['field_type'] = form_field.field_type - m['field_value'] = m['field_value'] - m['sort'] = form_field.sort - m['operation_record'] = wr - wrds.append(OperationRecordItem(**m)) - OperationRecordItem.objects.bulk_create(wrds) - return Response()