diff --git a/hb_server/apps/pm/filters.py b/hb_server/apps/pm/filters.py new file mode 100644 index 0000000..313c63d --- /dev/null +++ b/hb_server/apps/pm/filters.py @@ -0,0 +1,27 @@ +from django_filters import rest_framework as filters +from apps.mtm.models import Material, Step +from apps.pm.models import SubProductionProgress +from apps.wpm.models import Operation, WProduct + +from apps.wpm.services import WpmServies + + +class SubproductionProgressFilterSet(filters.FilterSet): + + operation = filters.NumberFilter(method='filter_operation') + class Meta: + model = SubProductionProgress + fields = ['material', 'subproduction_plan', 'operation', 'type'] + + def filter_operation(self, queryset, name, value): + operation = Operation.objects.get(pk=value) + wproducts = WProduct.objects.filter(ow_wproduct__operation=value) + step = operation.step + if wproducts.exists(): + subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts) + else: + subplans = WpmServies.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=Material.MA_TYPE_HALFGOOD) + return queryset \ No newline at end of file diff --git a/hb_server/apps/pm/migrations/0015_auto_20211122_1556.py b/hb_server/apps/pm/migrations/0015_auto_20211122_1556.py new file mode 100644 index 0000000..1f00fa9 --- /dev/null +++ b/hb_server/apps/pm/migrations/0015_auto_20211122_1556.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.9 on 2021-11-22 07:56 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0014_subproductionplan_number'), + ] + + operations = [ + migrations.AddField( + model_name='subproductionplan', + name='main_count_ok', + field=models.IntegerField(default=0, verbose_name='合格数'), + ), + migrations.AddField( + model_name='subproductionprogress', + name='count_ok', + field=models.IntegerField(default=0, verbose_name='合格数量'), + ), + ] diff --git a/hb_server/apps/pm/models.py b/hb_server/apps/pm/models.py index fa4711f..9cdd6c1 100644 --- a/hb_server/apps/pm/models.py +++ b/hb_server/apps/pm/models.py @@ -56,6 +56,7 @@ class SubProductionPlan(CommonAModel): main_product = models.ForeignKey(Material, verbose_name='主要产品', on_delete=models.CASCADE, null=True, blank=True) main_count = models.IntegerField('应产出数', default=0) main_count_real = models.IntegerField('实际产出数', default=0) + main_count_ok = models.IntegerField('合格数', default=0) steps = models.JSONField('工艺步骤', default=list) @@ -80,3 +81,4 @@ class SubProductionProgress(BaseModel): count = models.IntegerField('应出入数') count_pick = models.IntegerField('实际领用数', default=0) count_real = models.IntegerField('实际消耗/产出数', default=0) + count_ok = models.IntegerField('合格数量', default=0) diff --git a/hb_server/apps/pm/urls.py b/hb_server/apps/pm/urls.py index f6f6279..1d3f1eb 100644 --- a/hb_server/apps/pm/urls.py +++ b/hb_server/apps/pm/urls.py @@ -1,4 +1,4 @@ -from apps.pm.views import ProductionPlanViewSet, ResourceViewSet, SubProductionPlanViewSet +from apps.pm.views import ProductionPlanViewSet, ResourceViewSet, SubProductionPlanViewSet, SubProductionProgressViewSet from django.db.models import base from rest_framework import urlpatterns from django.urls import path, include @@ -7,6 +7,7 @@ from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register('production_plan', ProductionPlanViewSet, basename='production_plan') router.register('subproduction_plan', SubProductionPlanViewSet, basename='subproduction_plan') +router.register('subproduction_progress', SubProductionProgressViewSet, basename='subproduction_progress') router.register('resource', ResourceViewSet, basename='resource') urlpatterns = [ path('', include(router.urls)), diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py index 56446bf..aa02784 100644 --- a/hb_server/apps/pm/views.py +++ b/hb_server/apps/pm/views.py @@ -1,4 +1,5 @@ from datetime import timezone +from typing import List from django.db import transaction from rest_framework import serializers from rest_framework.views import APIView @@ -7,6 +8,7 @@ from apps.em.serializers import EquipmentSerializer from apps.inm.models import MaterialBatch from apps.inm.serializers import MaterialBatchSerializer from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep +from apps.pm.filters import SubproductionProgressFilterSet from apps.system.mixins import CreateUpdateModelAMixin from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin @@ -67,7 +69,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel return Response() @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PlanDestorySerializer) - def destory(self, request, pk=None): + def deletes(self, request, pk=None): """ 批量物理删除 """ @@ -178,6 +180,17 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo have = MaterialBatchSerializer(instance=objs, many=True).data return Response({'need':need, 'have':have}) +class SubProductionProgressViewSet(ListModelMixin, GenericViewSet): + """ + 生产进度 + """ + perms_map = {'*': '*'} + queryset = SubProductionProgress.objects.select_related('material', 'subproduction_plan') + search_fields = [] + serializer_class = SubProductionProgressSerializer + filterset_class = SubproductionProgressFilterSet + ordering_fields = ['id'] + ordering = ['id'] class ResourceViewSet(GenericViewSet): diff --git a/hb_server/apps/wpm/filters.py b/hb_server/apps/wpm/filters.py index f14d741..eac725e 100644 --- a/hb_server/apps/wpm/filters.py +++ b/hb_server/apps/wpm/filters.py @@ -1,4 +1,7 @@ from django_filters import rest_framework as filters +from apps.mtm.models import Material, Step + +from apps.wpm.services import WpmServies from .models import Operation, WMaterial, WProduct class WMaterialFilterSet(filters.FilterSet): @@ -6,12 +9,15 @@ class WMaterialFilterSet(filters.FilterSet): operation = filters.NumberFilter(method='filter_operation') class Meta: model = WMaterial - fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop'] + fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop', 'operation'] def filter_operation(self, queryset, name, value): operation = Operation.objects.get(pk=value) wproducts = WProduct.objects.filter(ow_wproduct__operation=value) + step = operation.step if wproducts.exists(): - pass + subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts) else: - pass \ No newline at end of file + subplans = WpmServies.get_subplans_queyset_from_step(step) + queryset = queryset.filter(subproduction_plan__in=subplans).exclude(material__type=Material.MA_TYPE_HALFGOOD) + return queryset \ No newline at end of file diff --git a/hb_server/apps/wpm/migrations/0020_alter_operationwproduct_wproduct.py b/hb_server/apps/wpm/migrations/0020_alter_operationwproduct_wproduct.py new file mode 100644 index 0000000..45929df --- /dev/null +++ b/hb_server/apps/wpm/migrations/0020_alter_operationwproduct_wproduct.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.9 on 2021-11-22 07:56 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0019_auto_20211122_1110'), + ] + + operations = [ + migrations.AlterField( + model_name='operationwproduct', + name='wproduct', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ow_wproduct', to='wpm.wproduct', verbose_name='关联半成品'), + ), + ] diff --git a/hb_server/apps/wpm/migrations/0021_auto_20211123_0945.py b/hb_server/apps/wpm/migrations/0021_auto_20211123_0945.py new file mode 100644 index 0000000..c8b651a --- /dev/null +++ b/hb_server/apps/wpm/migrations/0021_auto_20211123_0945.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.9 on 2021-11-23 01:45 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0020_alter_operationwproduct_wproduct'), + ] + + operations = [ + migrations.RemoveField( + model_name='operationwproduct', + name='production_plan', + ), + migrations.RemoveField( + model_name='wproduct', + name='production_plan', + ), + ] diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index f2d3f5f..ee835a1 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -43,7 +43,6 @@ class WProduct(CommonAModel): parent = models.JSONField('父', default=list, blank=True) 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') - production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE) warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True) operation = models.ForeignKey('wpm.operation', verbose_name='关联操作', on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation') @@ -66,7 +65,6 @@ class OperationWproduct(BaseModel): number = models.CharField('物品编号', null=True, blank=True, max_length=50) material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE) - production_plan = models.ForeignKey(ProductionPlan, verbose_name='当前主生产计划', on_delete=models.CASCADE) class OperationMaterial(BaseModel): diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 78b0ecc..3b87574 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -326,12 +326,13 @@ class OperationMaterialCreate1Serailizer(serializers.ModelSerializer): class Meta: model = OperationMaterial fields = ['operation', 'wmaterial', 'count'] - + def create(self, validated_data): wmaterial = validated_data['wmaterial'] validated_data['material'] = wmaterial.material validated_data['subproduction_plan'] = wmaterial.subproduction_plan validated_data['batch'] = wmaterial.batch + validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_IN return super().create(validated_data) class OperationMaterialCreate2Serailizer(serializers.ModelSerializer): @@ -344,6 +345,7 @@ class OperationMaterialCreate2Serailizer(serializers.ModelSerializer): subproduction_progress = validated_data['subproduction_progress'] validated_data['material'] = subproduction_progress.material validated_data['subproduction_plan'] = subproduction_progress.subproduction_plan + validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_OUT return super().create(validated_data) class OperationMaterialCreate3Serializer(serializers.ModelSerializer): @@ -351,5 +353,9 @@ class OperationMaterialCreate3Serializer(serializers.ModelSerializer): class Meta: model = OperationMaterial fields = ['operation', 'material'] + + def create(self, validated_data): + validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_TOOL + return super().create(validated_data) \ No newline at end of file diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index bc1b8b7..c0fc856 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -69,7 +69,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']]) wps.update(step=first_step, is_executed=False, act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None, - subproduction_plan=sp, production_plan=sp.production_plan, update_by=request.user, update_time=timezone.now()) + subproduction_plan=sp, update_by=request.user, update_time=timezone.now()) return Response() @@ -84,7 +84,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): vdata = serializer.data subplan = self.get_object() material = subplan.main_product - batch = subplan.production_plan.number + batch = subplan.number warehouse = WareHouse.objects.get(id=vdata['warehouse']) wproducts = WProduct.objects.filter(subproduction_plan=subplan, act_state=WProduct.WPR_ACT_STATE_OK, material=material, is_deleted=False) @@ -160,7 +160,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): perms_map={'*':'*'} queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False).exclude(operation=None) serializer_class = WProductListSerializer - filterset_fields = ['step', 'subproduction_plan', 'material', 'production_plan', 'step__process', 'act_state'] + filterset_fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state'] search_fields = ['number'] ordering_fields = ['id'] ordering = ['id'] @@ -207,7 +207,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): # 更新子计划主产品数 instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) - instance.count_real = instance.count_real + 1 # 这个地方可能会有问题 + instance.count_ok = instance.count_ok + 1 # 这个地方可能会有问题 instance.save() else:# 如果不合格 pass @@ -228,7 +228,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): if wproduct.act_state != WProduct.WPR_ACT_STATE_OK: raise exceptions.APIException('半成品不可入库') material = wproduct.material - batch = wproduct.production_plan.number + batch = wproduct.subproduction_plan.number # 创建入库记录 remark = vdata.get('remark', '') fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN, @@ -314,7 +314,6 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd owp['number'] = wpd.number owp['material'] = wpd.material owp['subproduction_plan'] = wpd.subproduction_plan - owp['production_plan'] = wpd.production_plan owps.append(OperationWproduct(**owp)) OperationWproduct.objects.bulk_create(owps) else: @@ -343,9 +342,90 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd opm.save() return Response() - - - + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) + @transaction.atomic + def submit(self, request, pk=None): + """ + 提交车间操作重要 + """ + op = self.get_object() + step = op.step + # 检查自定义表单填写 + if OperationRecord.objects.filter(operation=op, is_filled=False).exists(): + raise exceptions.APIException('存在自定义表单未填写') + # 更新物料消耗进度 + for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_IN): + # 更新车间物料 + i_wmat = i.wmaterial + i_wmat.count = i_wmat.count- i['count'] + i_wmat.save() + # 更新子计划物料消耗情况 + sp = i_wmat.subproduction_plan + sp.count_real = sp.count_real + i['count'] + sp.save() + # 更新产出 + for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT): + if not i.subproduction_progress.is_main: + # 更新车间物料产出情况 + ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i.subproduction_plan, + material=i.material) + ins.count = ins.count + i['count'] + ins.save() + # 更新子计划物料产出情况 + sp = i.subproduction_progress + sp.count_real = sp.count_real + i['count'] + sp.save() + # 更新动态产品表 + if step.type == Step.STEP_TYPE_NOM: + for i in OperationWproduct.objects.filter(operation=op): + wp = i.wproduct + wsp = i.subproduction_plan + # 获取下一步子工序 + newstep, hasNext = WpmServies.get_next_step(wsp, step) + wp.step = newstep + wp.pre_step = step + if hasNext: + wp.is_executed= False + else: + wp.is_executed = True + wp.act_state = WProduct.WPR_ACT_STATE_TOTEST + wp.material = wsp.main_product + # 更新子计划进度 + instance = SubProductionProgress.objects.get(subproduction_plan=wsp, + is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) + instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨 + instance.save() + wp.operation = None + wp.save() + elif step.type == Step.STEP_TYPE_DIV: + # 更新物料产出情况 + for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT): + if i.subproduction_progress.is_main: + newstep, _ = WpmServies.get_next_step(i.subproduction_plan, step) + wpr = dict(material=i.material, step=newstep, + act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='', + subproduction_plan=i.subproduction_plan) + for x in range(i.count): + WProduct.objects.create(**wpr) + elif step.type == Step.STEP_TYPE_COMB: + # 隐藏原半成品 + ows = OperationWproduct.objects.filter(operation=op) + ows.update(is_hidden=True) + if i.subproduction_progress.is_main: + newstep, hasNext = WpmServies.get_next_step(i.subproduction_plan, step) + wproduct = WProduct() + wproduct.material = i.material + wproduct.step = newstep + wproduct.subproduction_plan = i.subproduction_plan + wproduct.parent = ows.values_list('wproduct', flat=True) + if hasNext: + wproduct.act_state = WProduct.WPR_ACT_STATE_DOING + wproduct.is_executed = False + else: + wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST + wproduct.is_executed = True + wproduct.save() + class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): @@ -581,7 +661,6 @@ class DoFormSubmit(CreateAPIView, GenericAPIView): owp['number'] = wp.number owp['material'] = wp.material owp['subproduction_plan'] = wp.subproduction_plan - owp['production_plan'] = wp.production_plan owps.append(OperationWproduct(**owp)) OperationWproduct.objects.bulk_create(owps) @@ -611,8 +690,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView): newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) wpr = dict(material=ma, step=newstep, act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='', - subproduction_plan=i['subproduction_plan'], - production_plan=i['subproduction_plan'].production_plan) + subproduction_plan=i['subproduction_plan']) for x in range(i['count_output']): WProduct.objects.create(**wpr) else: @@ -641,7 +719,6 @@ class DoFormSubmit(CreateAPIView, GenericAPIView): wproduct.material = vdata['subproduction_plan'].main_product wproduct.step = newstep wproduct.subproduction_plan=vdata['subproduction_plan'] - wproduct.production_plan=vdata['subproduction_plan'].production_plan wproduct.parent = data['wproducts'] if hasNext: wproduct.act_state=WProduct.WPR_ACT_STATE_DOING diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py index 07d1c30..8b07565 100644 --- a/hb_server/utils/view.py +++ b/hb_server/utils/view.py @@ -62,7 +62,7 @@ class UpdateDevelop(APIView): import os # 更新后端 os.chdir('/home/hberp') - ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git origin develop') + ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git develop') # 打包前端 # os.chdir('/home/hberp/hb_client') # os.system('npm run build:prod')