From f939b827a88d287826b619fbb3ba6c50fefa224f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 18 Nov 2021 15:07:54 +0800 Subject: [PATCH 01/36] =?UTF-8?q?=E5=8D=8A=E6=88=90=E5=93=81=E8=A1=A8?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E9=A2=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/models.py | 4 ++-- hb_server/apps/wpm/serializers.py | 32 +++++++++++++++++++++++++ hb_server/apps/wpm/views.py | 40 +++++++++++++++++++++---------- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 8ec6790..2f0007e 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -4,7 +4,7 @@ import django.utils.timezone as timezone from django.db.models.query import QuerySet from apps.inm.models import WareHouse from apps.pm.models import ProductionPlan, SubProductionPlan -from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File +from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm @@ -45,7 +45,7 @@ class WProduct(CommonAModel): 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) -class Operation(CommonAModel): +class Operation(CommonADModel): """ 生产操作 """ diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index fc6be42..aad7ef7 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -14,6 +14,7 @@ from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, Ope from django.db import transaction class PickHalfSerializer(serializers.Serializer): + id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID') wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID'), required=False) # 从半成品表里直接修改状态 class PickDetailSerializer(serializers.Serializer): @@ -148,6 +149,37 @@ class OperationListSerializer(serializers.ModelSerializer): model = Operation fields = '__all__' +class OperationCreateSerializer(serializers.Serializer): + """ + 操作创建 + """ + step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID") + # subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False) + wproducts = serializers.ListField(child= + serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False) + + def validate(self, data): + # subproduction_plan = data['subproduction_plan'] + step = data['step'] + + # stepIds=[i['id'] for i in subproduction_plan.steps] + # if step.id not in stepIds: + # raise exceptions.ValidationError('请选择正确的子工序操作') + + if 'wproducts' in data and data['wproducts']: + if step.type == Step.STEP_TYPE_DIV: + raise exceptions.ValidationError(_('不可进行此操作')) + for i in data['wproducts']: + if i.is_executed: + raise exceptions.ValidationError('不可进行操作') + # if i.subproduction_plan != subproduction_plan: + # raise exceptions.ValidationError('半成品所属子计划不一致') + if i.step != step: + raise exceptions.ValidationError('半成品所属子工序不一致') + else: + if step.type != Step.STEP_TYPE_DIV: + raise exceptions.ValidationError(_('请选择半成品进行操作')) + return data class OperationInitSerializer(serializers.Serializer): step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID") diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 1b63890..cab6c45 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -1,6 +1,6 @@ from django.shortcuts import render from rest_framework.generics import CreateAPIView, GenericAPIView -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin +from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.utils import serializer_helpers from rest_framework.utils.field_mapping import get_relation_kwargs from rest_framework.views import APIView @@ -10,14 +10,14 @@ from apps.inm.signals import update_inm from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial, TechDoc from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer from apps.pm.models import SubProductionPlan, SubProductionProgress -from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer +from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from apps.qm.models import TestRecordItem from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action from apps.wpm.models import OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem -from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer +from apps.wpm.serializers import OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers @@ -49,19 +49,25 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): """ 领半成品 """ - mIds = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN, - material__type=Material.MA_TYPE_HALFGOOD).values_list('material', flat=True) - queyset = WProduct.objects.filter(is_hidden=False, material__in=mIds, act_state=WProduct.WPR_ACT_STATE_OK) - return Response(WProductListSerializer(instance=queyset, many=True).data) + spps = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN, + material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material') + return Response(SubProductionProgressSerializer(instance=spps, many=True).data) elif request.method=='POST': serializer= PickHalfSerializer(data=request.data) serializer.is_valid(raise_exception=True) vdata = serializer.data - wps = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']]) first_step = Step.objects.get(pk=sp.steps[0].id) - 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) + for i in vdata: + if 'wproducts' in i and len(i['wproducts'])>0: + spp = SubProductionProgress.objects.get(pk=i['id']) + spp.count_pick = spp.count_pick + len(i['wproducts']) + if spp.count_pick > spp.count: + raise exceptions.APIException('超过计划数') + spp.save() + 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) return Response() @@ -253,7 +259,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): wproduct.save() return Response() -class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): +class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericViewSet): """ 生产操作记录 """ @@ -267,8 +273,18 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): def get_serializer_class(self): if self.action == 'retrieve': return OperationDetailSerializer + elif self.action == 'create': + return OperationCreateSerializer return super().get_serializer_class() + @transaction.atomic + def create(self, request, *args, **kwargs): + data = request.data + serializer = OperationCreateSerializer(data=data, context={'request':self.request}) + serializer.is_valid(raise_exception=True) + vdata = serializer.validated_data #校验之后的数据 + return Response() + class DoFormInit(CreateAPIView, GenericAPIView): perms_map={'*':'*'} serializer_class=OperationInitSerializer From 8a41c1728ef18577c96dbf199f24827c2245a224 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 18 Nov 2021 16:12:23 +0800 Subject: [PATCH 02/36] =?UTF-8?q?=E4=BB=8E=E5=8D=8A=E6=88=90=E5=93=81?= =?UTF-8?q?=E9=A2=86=E6=96=99bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/serializers.py | 6 ++++++ hb_server/apps/qm/models.py | 6 +++++- hb_server/apps/wpm/models.py | 2 ++ hb_server/apps/wpm/views.py | 2 +- hb_server/requirements.txt | 2 +- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py index 3e7a46d..f9cc55d 100644 --- a/hb_server/apps/mtm/serializers.py +++ b/hb_server/apps/mtm/serializers.py @@ -209,6 +209,12 @@ class RecordFormDetailSerializer(serializers.ModelSerializer): def get_form_fields(self, obj): serializer = RecordFormFieldSerializer(instance=RecordFormField.objects.filter(form=obj, is_deleted=False), many=True) + vdata = serializer.data + if obj.type == RecordForm.RF_TYPE_TEST: + for i in vdata: + if i['need_judge']: + i['is_testok'] = False + i['is_teskok_robot'] = False return serializer.data diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index fb61f53..c2dea88 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -49,8 +49,11 @@ class TestRecord(CommonAModel): """ form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE) is_testok = models.BooleanField('是否合格', default=True) + is_testok_robot = models.BooleanField('自动判定的是否合格', default=True) + number = models.CharField('产品编号', null=True, blank=True, max_length=50) wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True) material = models.ForeignKey('mtm.material', verbose_name='关联的物料状态', on_delete=models.CASCADE, null=True, blank=True) + subproduction_plan = models.ForeignKey('pm.subproductionplan', verbose_name='关联的生产子计划', on_delete=models.CASCADE, null=True, blank=True) fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True) remark = models.TextField('备注', default='') @@ -66,5 +69,6 @@ class TestRecordItem(BaseModel): field_value = models.JSONField('录入值', default=dict, blank=True) need_judge = models.BooleanField('是否需要判定', default=False) sort = models.IntegerField('排序号', default=1) - is_testok = models.BooleanField('是否合格', null=True, blank=True) + is_testok = models.BooleanField('是否合格', null=True, blank=True) + is_testok_robot = models.BooleanField('自动判定的是否合格', null=True, blank=True) test_record = models.ForeignKey(TestRecord, verbose_name='关联的检测记录', on_delete=models.CASCADE, related_name='item_test_record') \ No newline at end of file diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 2f0007e..80e1b0c 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -44,6 +44,8 @@ class WProduct(CommonAModel): subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE) 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='') class Operation(CommonADModel): """ diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index cab6c45..91d205d 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -53,7 +53,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material') return Response(SubProductionProgressSerializer(instance=spps, many=True).data) elif request.method=='POST': - serializer= PickHalfSerializer(data=request.data) + serializer= PickHalfSerializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) vdata = serializer.data first_step = Step.objects.get(pk=sp.steps[0].id) diff --git a/hb_server/requirements.txt b/hb_server/requirements.txt index a223cbc..3d3b1be 100644 --- a/hb_server/requirements.txt +++ b/hb_server/requirements.txt @@ -1,5 +1,5 @@ celery==5.1.2 -Django==3.2.6 +Django==3.2.9 django-celery-beat==2.2.1 django-cors-headers==3.7.0 django-filter==2.4.0 From b8495ee431fcbf068866fb3d1e9cd26728f8f5a2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 18 Nov 2021 16:49:22 +0800 Subject: [PATCH 03/36] =?UTF-8?q?=E4=BB=8E=E5=8D=8A=E6=88=90=E5=93=81?= =?UTF-8?q?=E9=A2=86=E6=96=99bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/models.py | 2 +- hb_server/apps/wpm/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 80e1b0c..6e2f647 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -45,7 +45,7 @@ class WProduct(CommonAModel): 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='') + # on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation') class Operation(CommonADModel): """ diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 91d205d..6244191 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -56,7 +56,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): serializer= PickHalfSerializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) vdata = serializer.data - first_step = Step.objects.get(pk=sp.steps[0].id) + first_step = Step.objects.get(pk=sp.steps[0]['id']) for i in vdata: if 'wproducts' in i and len(i['wproducts'])>0: spp = SubProductionProgress.objects.get(pk=i['id']) From bd179c20b1403820928b6281d373789ef0082f4f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 19 Nov 2021 10:40:09 +0800 Subject: [PATCH 04/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E9=87=8D=E6=96=B0=E6=A2=B3=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/serializers.py | 2 +- .../0014_subproductionplan_number.py | 18 ++++++ hb_server/apps/pm/models.py | 1 + hb_server/apps/pm/serializers.py | 5 ++ hb_server/apps/pm/views.py | 6 +- .../qm/migrations/0011_auto_20211119_0848.py | 35 +++++++++++ .../wpm/migrations/0016_auto_20211119_0848.py | 28 +++++++++ .../wpm/migrations/0017_auto_20211119_1034.py | 49 +++++++++++++++ hb_server/apps/wpm/models.py | 15 +++-- hb_server/apps/wpm/serializers.py | 15 ++--- hb_server/apps/wpm/urls.py | 3 +- hb_server/apps/wpm/views.py | 62 ++++++++++++++++--- hb_server/utils/tools.py | 2 +- 13 files changed, 216 insertions(+), 25 deletions(-) create mode 100644 hb_server/apps/pm/migrations/0014_subproductionplan_number.py create mode 100644 hb_server/apps/qm/migrations/0011_auto_20211119_0848.py create mode 100644 hb_server/apps/wpm/migrations/0016_auto_20211119_0848.py create mode 100644 hb_server/apps/wpm/migrations/0017_auto_20211119_1034.py diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py index f9cc55d..f1b3ab8 100644 --- a/hb_server/apps/mtm/serializers.py +++ b/hb_server/apps/mtm/serializers.py @@ -26,7 +26,7 @@ class MaterialDetailSerializer(serializers.ModelSerializer): class MaterialSimpleSerializer(serializers.ModelSerializer): class Meta: model = Material - fields = ['id', 'name', 'number', 'unit','specification'] + fields = ['id', 'name', 'number', 'unit','specification', 'type'] class ProcessSerializer(serializers.ModelSerializer): instruction_ = FileSimpleSerializer(source='instruction', read_only=True) diff --git a/hb_server/apps/pm/migrations/0014_subproductionplan_number.py b/hb_server/apps/pm/migrations/0014_subproductionplan_number.py new file mode 100644 index 0000000..e84a4d8 --- /dev/null +++ b/hb_server/apps/pm/migrations/0014_subproductionplan_number.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-11-19 02:34 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0013_alter_subproductionplan_subproduction'), + ] + + operations = [ + migrations.AddField( + model_name='subproductionplan', + name='number', + field=models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='子计划编号'), + ), + ] diff --git a/hb_server/apps/pm/models.py b/hb_server/apps/pm/models.py index 663d885..fa4711f 100644 --- a/hb_server/apps/pm/models.py +++ b/hb_server/apps/pm/models.py @@ -44,6 +44,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) subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subplan_subprod') start_date = models.DateField('计划开工日期') diff --git a/hb_server/apps/pm/serializers.py b/hb_server/apps/pm/serializers.py index 90ff400..65980c0 100644 --- a/hb_server/apps/pm/serializers.py +++ b/hb_server/apps/pm/serializers.py @@ -55,3 +55,8 @@ class PickNeedSerializer(serializers.Serializer): class PlanDestorySerializer(serializers.Serializer): ids = serializers.ListField(child=serializers.IntegerField(), label='主计划ID列表') + +class SubproductionPlanSimpleSerializer(serializers.ModelSerializer): + class Meta: + model = SubProductionPlan + fields = ['id', 'number'] diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py index a86d146..56446bf 100644 --- a/hb_server/apps/pm/views.py +++ b/hb_server/apps/pm/views.py @@ -62,7 +62,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel pass else: raise APIException('排产数量错误') - instance = serializer.save(create_by=request.user, product=order.product, number='JH-'+ranstr(7)) + instance = serializer.save(create_by=request.user, product=order.product, number='JH'+ranstr(7)) updateOrderPlanedCount(instance.order) return Response() @@ -83,13 +83,13 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel if production_plan.is_planed: raise APIException('已生成子计划') subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number') - for i in subps: + 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') 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, - steps = list(steps)) + steps = list(steps), number=production_plan.number + '-' + str(index+1)) # 生成子计划物料需求/进度 for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'): spro = SubProductionProgress.objects.create(material=m.material, type=m.type, diff --git a/hb_server/apps/qm/migrations/0011_auto_20211119_0848.py b/hb_server/apps/qm/migrations/0011_auto_20211119_0848.py new file mode 100644 index 0000000..a643fe0 --- /dev/null +++ b/hb_server/apps/qm/migrations/0011_auto_20211119_0848.py @@ -0,0 +1,35 @@ +# Generated by Django 3.2.9 on 2021-11-19 00:48 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0013_alter_subproductionplan_subproduction'), + ('qm', '0010_rename_m_state_testrecord_material'), + ] + + operations = [ + migrations.AddField( + model_name='testrecord', + name='is_testok_robot', + field=models.BooleanField(default=True, verbose_name='自动判定的是否合格'), + ), + migrations.AddField( + model_name='testrecord', + name='number', + field=models.CharField(blank=True, max_length=50, null=True, verbose_name='产品编号'), + ), + migrations.AddField( + model_name='testrecord', + name='subproduction_plan', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联的生产子计划'), + ), + migrations.AddField( + model_name='testrecorditem', + name='is_testok_robot', + field=models.BooleanField(blank=True, null=True, verbose_name='自动判定的是否合格'), + ), + ] diff --git a/hb_server/apps/wpm/migrations/0016_auto_20211119_0848.py b/hb_server/apps/wpm/migrations/0016_auto_20211119_0848.py new file mode 100644 index 0000000..e632e92 --- /dev/null +++ b/hb_server/apps/wpm/migrations/0016_auto_20211119_0848.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.9 on 2021-11-19 00:48 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0015_auto_20211117_2332'), + ] + + operations = [ + migrations.RemoveField( + model_name='operation', + name='wproducts', + ), + migrations.AddField( + model_name='operation', + name='is_submited', + field=models.BooleanField(default=True, verbose_name='是否提交'), + ), + migrations.AddField( + model_name='wproduct', + name='operation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='current_operation', to='wpm.operation', verbose_name='关联操作'), + ), + ] diff --git a/hb_server/apps/wpm/migrations/0017_auto_20211119_1034.py b/hb_server/apps/wpm/migrations/0017_auto_20211119_1034.py new file mode 100644 index 0000000..bbbaeaa --- /dev/null +++ b/hb_server/apps/wpm/migrations/0017_auto_20211119_1034.py @@ -0,0 +1,49 @@ +# Generated by Django 3.2.9 on 2021-11-19 02:34 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('em', '0009_auto_20210916_1108'), + ('wpm', '0016_auto_20211119_0848'), + ] + + operations = [ + migrations.RemoveField( + model_name='operationrecord', + name='create_by', + ), + migrations.RemoveField( + model_name='operationrecord', + name='update_by', + ), + migrations.AddField( + model_name='operationrecord', + name='is_filled', + field=models.BooleanField(default=True, verbose_name='是否填写'), + ), + migrations.AlterField( + model_name='operation', + name='is_submited', + field=models.BooleanField(default=False, verbose_name='是否提交'), + ), + migrations.CreateModel( + name='OperationEquip', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')), + ('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')), + ('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')), + ('remark', models.TextField(blank=True, null=True, verbose_name='备注')), + ('equip', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='em.equipment', verbose_name='生产设备')), + ('operation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.operation', verbose_name='关联操作')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 6e2f647..a00724e 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -9,6 +9,7 @@ from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm from django.core.validators import MinValueValidator +from apps.em.models import Equipment class WMaterial(BaseModel): """ 车间生产物料 @@ -44,17 +45,17 @@ class WProduct(CommonAModel): subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE) 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') + operation = models.ForeignKey('wpm.operation', verbose_name='关联操作', + on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation') class Operation(CommonADModel): """ 生产操作 """ - wproducts = models.ManyToManyField(WProduct, verbose_name='关联半成品', through='wpm.operationwproduct') step = models.ForeignKey(Step, verbose_name='操作步骤', on_delete=models.CASCADE, null=True, blank=True) use_scrap = models.BooleanField('是否使用的边角料', default=False) remark = models.CharField('操作备注', max_length=200, null=True, blank=True) + is_submited = models.BooleanField('是否提交', default=False) class OperationWproduct(BaseModel): """ @@ -82,13 +83,13 @@ class OperationMaterial(BaseModel): material = models.ForeignKey(Material, verbose_name='可能产出的副产品', on_delete=models.CASCADE, null=True, blank=True) count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)]) -class OperationRecord(CommonAModel): +class OperationRecord(BaseModel): """ 记录表格 """ form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE) operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE) - + is_filled = models.BooleanField('是否填写', default=True) class OperationRecordItem(BaseModel): """ @@ -102,3 +103,7 @@ class OperationRecordItem(BaseModel): sort = models.IntegerField('排序号', default=1) operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE) +class OperationEquip(BaseModel): + operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE) + equip = models.ForeignKey(Equipment, verbose_name='生产设备', on_delete=models.CASCADE) + remark = models.TextField('备注', null=True, blank=True) \ No newline at end of file diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index aad7ef7..a79a118 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -8,9 +8,10 @@ from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer from apps.pm.models import SubProductionPlan, SubProductionProgress from django.utils import timezone from django.utils.translation import gettext_lazy as _ +from apps.pm.serializers import SubproductionPlanSimpleSerializer from apps.qm.models import TestRecord, TestRecordItem from apps.system.serializers import UserSimpleSerializer -from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, OperationRecordItem +from apps.wpm.models import Operation, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem from django.db import transaction class PickHalfSerializer(serializers.Serializer): @@ -130,20 +131,14 @@ class WProductListSerializer(serializers.ModelSerializer): fields = '__all__' class OperationDetailSerializer(serializers.ModelSerializer): - wproducts_ = serializers.SerializerMethodField() create_by_ = UserSimpleSerializer(source='create_by', read_only=True) - material_ = MaterialSimpleSerializer(source='material', read_only=True) step_ = StepSimpleSerializer(source='step', read_only=True) class Meta: model = Operation fields = '__all__' - - def get_wproducts_(self, obj): - return list(WProduct.objects.filter(id__in=obj.wproducts).values('id', 'number')) class OperationListSerializer(serializers.ModelSerializer): create_by_ = UserSimpleSerializer(source='create_by', read_only=True) - material_ = MaterialSimpleSerializer(source='material', read_only=True) step_ = StepSimpleSerializer(source='step', read_only=True) class Meta: model = Operation @@ -231,6 +226,12 @@ class OperationRecordSerializer(serializers.ModelSerializer): model = OperationRecord fields = ['form', 'record_data'] +class OperationWproductListSerializer(serializers.ModelSerializer): + material_ = MaterialSimpleSerializer(source='material', read_only=True) + subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True) + class Meta: + model = OperationWproduct + fields = '__all__' class OperationSubmitSerializer(serializers.Serializer): diff --git a/hb_server/apps/wpm/urls.py b/hb_server/apps/wpm/urls.py index 7c43ac7..b5d4018 100644 --- a/hb_server/apps/wpm/urls.py +++ b/hb_server/apps/wpm/urls.py @@ -3,12 +3,13 @@ from rest_framework import urlpatterns from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.wpm.views import DoFormInit, DoFormSubmit, OperationViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet +from apps.wpm.views import DoFormInit, DoFormSubmit, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet router = DefaultRouter() router.register('wmaterial', WMaterialViewSet, basename='wmaterial') router.register('wproduct', WProductViewSet, basename='wproduct') router.register('operation', OperationViewSet, basename='operation') +router.register('operation_wproduct', OperationWproductViewSet, basename='operation_wproduct') router.register('subplan', WPlanViewSet, basename='wplan') urlpatterns = [ path('do/init/', DoFormInit.as_view()), diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 6244191..913712a 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -15,9 +15,9 @@ from apps.qm.models import TestRecordItem from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action -from apps.wpm.models import OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem +from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem -from apps.wpm.serializers import OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer +from apps.wpm.serializers import OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers @@ -67,7 +67,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) + subproduction_plan=sp, production_plan=sp.production_plan, update_by=request.user, update_time=timezone.now()) return Response() @@ -125,7 +125,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): IProduct.objects.bulk_create(ips2) # 更新库存并修改半成品进行状态 update_inm(fifo) - wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse) + wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user, update_time=timezone.now()) return Response() @@ -156,7 +156,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): 半成品 """ perms_map={'*':'*'} - queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False) + 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'] search_fields = ['number'] @@ -199,7 +199,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): if obj.is_testok: wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.number is None: # 产生半成品编号 - wproduct.number = 'WP-'+ranstr(7) + wproduct.number = 'WP'+ranstr(7) wproduct.save() # 更新子计划状态 # 更新子计划主产品数 @@ -266,7 +266,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen perms_map={'*':'*'} queryset = Operation.objects.select_related('step', 'material').all() serializer_class = OperationListSerializer - filterset_fields = ['step', 'step__process'] + filterset_fields = ['step', 'step__process', 'is_submited'] ordering_fields = ['id'] ordering = ['-id'] @@ -283,8 +283,56 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen serializer = OperationCreateSerializer(data=data, context={'request':self.request}) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data #校验之后的数据 + step = Step.objects.get(pk=vdata['step']) + op = Operation() + op.step = step + op.is_submited = False + op.save() + # 创建操作所用半成品关联记录 + if 'wproducts' in vdata: + owps = [] + for i in vdata['wproducts']: + owp = {} + wpd = WProduct.objects.get(pk=i) + owp['operation'] = op + owp['wproduct'] = wpd + 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) + # 查询需要填写的自定义表格 + forms = RecordForm.objects.filter(step=step, type=RecordForm.RF_TYPE_DO) + for i in forms: + opr = OperationRecord() + opr.operation = op + opr.form = i + opr.is_filled = False + opr.save() + # 查询需要使用的生产设备 + equips = step.equipements + for i in equips: + ope = OperationEquip() + ope.operation = op + ope.equip = i + ope.save() return Response() + + + +class OperationWproductViewSet(ListModelMixin, GenericViewSet): + """ + 操作使用的半成品 + """ + perms_map={'*':'*'} + queryset = OperationWproduct.objects.select_related('subproduction_plan', 'material').all() + serializer_class = OperationWproductListSerializer + filterset_fields = ['material', 'subproduction_plan', 'operation'] + ordering_fields = ['id'] + ordering = ['-id'] + class DoFormInit(CreateAPIView, GenericAPIView): perms_map={'*':'*'} serializer_class=OperationInitSerializer diff --git a/hb_server/utils/tools.py b/hb_server/utils/tools.py index 786b8f2..73a6db6 100644 --- a/hb_server/utils/tools.py +++ b/hb_server/utils/tools.py @@ -2,6 +2,6 @@ import random import string def ranstr(num): - salt = ''.join(random.sample(string.ascii_letters + string.digits, num)) + salt = ''.join(random.sample(string.ascii_lowercase + string.digits, num)) return salt ranstr(10) \ No newline at end of file From 718845b39abf95318e7ad2ff7e375657fadd9a29 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 19 Nov 2021 10:46:16 +0800 Subject: [PATCH 05/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 913712a..18f7577 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -1,6 +1,6 @@ from django.shortcuts import render from rest_framework.generics import CreateAPIView, GenericAPIView -from rest_framework.mixins import CreateModelMixin, ListModelMixin, RetrieveModelMixin +from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.utils import serializer_helpers from rest_framework.utils.field_mapping import get_relation_kwargs from rest_framework.views import APIView @@ -264,7 +264,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen 生产操作记录 """ perms_map={'*':'*'} - queryset = Operation.objects.select_related('step', 'material').all() + queryset = Operation.objects.select_related('step').all() serializer_class = OperationListSerializer filterset_fields = ['step', 'step__process', 'is_submited'] ordering_fields = ['id'] From c6cae6e4552bcdb0938322da89c5976bca240b3e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 19 Nov 2021 11:05:23 +0800 Subject: [PATCH 06/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 18f7577..b496ebd 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -270,6 +270,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen ordering_fields = ['id'] ordering = ['-id'] + def get_queryset(self): + return self.queryset.filter(create_by=self.request.user) + def get_serializer_class(self): if self.action == 'retrieve': return OperationDetailSerializer @@ -283,7 +286,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen serializer = OperationCreateSerializer(data=data, context={'request':self.request}) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data #校验之后的数据 - step = Step.objects.get(pk=vdata['step']) + step = vdata['step'] op = Operation() op.step = step op.is_submited = False @@ -291,9 +294,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen # 创建操作所用半成品关联记录 if 'wproducts' in vdata: owps = [] - for i in vdata['wproducts']: + for wpd in vdata['wproducts']: owp = {} - wpd = WProduct.objects.get(pk=i) owp['operation'] = op owp['wproduct'] = wpd owp['number'] = wpd.number @@ -322,7 +324,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen -class OperationWproductViewSet(ListModelMixin, GenericViewSet): +class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): """ 操作使用的半成品 """ @@ -333,6 +335,18 @@ class OperationWproductViewSet(ListModelMixin, GenericViewSet): ordering_fields = ['id'] ordering = ['-id'] + @transaction.atomic() + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + instance.delete() + wp = instance.wproduct + wp.operation = None + wp.save() + return Response() + + class DoFormInit(CreateAPIView, GenericAPIView): perms_map={'*':'*'} serializer_class=OperationInitSerializer From 12895757acd5d507eef575ea7ad47080c2b57746 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 19 Nov 2021 11:08:09 +0800 Subject: [PATCH 07/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index b496ebd..1e4d2c8 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -313,13 +313,15 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen opr.is_filled = False opr.save() # 查询需要使用的生产设备 - equips = step.equipements + equips = step.equipments for i in equips: ope = OperationEquip() ope.operation = op ope.equip = i ope.save() return Response() + + From f21a599252bca7020364129a2ebe7cc80fb665fb Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 19 Nov 2021 11:11:51 +0800 Subject: [PATCH 08/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 1e4d2c8..df7aa0d 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -313,8 +313,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen opr.is_filled = False opr.save() # 查询需要使用的生产设备 - equips = step.equipments - for i in equips: + for i in step.equipments.all(): ope = OperationEquip() ope.operation = op ope.equip = i From d65f117303565e21c893e0430ed936375a860432 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 19 Nov 2021 13:42:24 +0800 Subject: [PATCH 09/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0018_auto_20211119_1340.py | 29 ++++++++++ hb_server/apps/wpm/models.py | 6 +- hb_server/apps/wpm/serializers.py | 40 ++++++++++++- hb_server/apps/wpm/views.py | 58 +++++++++++++++++-- 4 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 hb_server/apps/wpm/migrations/0018_auto_20211119_1340.py diff --git a/hb_server/apps/wpm/migrations/0018_auto_20211119_1340.py b/hb_server/apps/wpm/migrations/0018_auto_20211119_1340.py new file mode 100644 index 0000000..07b428c --- /dev/null +++ b/hb_server/apps/wpm/migrations/0018_auto_20211119_1340.py @@ -0,0 +1,29 @@ +# Generated by Django 3.2.9 on 2021-11-19 05:40 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0017_auto_20211119_1034'), + ] + + operations = [ + migrations.AlterField( + model_name='operationequip', + name='operation', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='oe_operation', to='wpm.operation', verbose_name='关联操作'), + ), + migrations.AlterField( + model_name='operationrecord', + name='operation', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='or_operation', to='wpm.operation', verbose_name='关联的生产操作'), + ), + migrations.AlterField( + model_name='operationwproduct', + name='operation', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ow_operation', to='wpm.operation', verbose_name='关联操作'), + ), + ] diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index a00724e..b15585d 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -61,7 +61,7 @@ class OperationWproduct(BaseModel): """ 生产操作半成品关联表 """ - operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE) + operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='ow_operation') wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE) number = models.CharField('物品编号', null=True, blank=True, max_length=50) material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE) @@ -88,7 +88,7 @@ class OperationRecord(BaseModel): 记录表格 """ form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE) - operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE) + operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE, related_name='or_operation') is_filled = models.BooleanField('是否填写', default=True) class OperationRecordItem(BaseModel): @@ -104,6 +104,6 @@ class OperationRecordItem(BaseModel): operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE) class OperationEquip(BaseModel): - operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE) + operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='oe_operation') equip = models.ForeignKey(Equipment, verbose_name='生产设备', on_delete=models.CASCADE) remark = models.TextField('备注', null=True, blank=True) \ No newline at end of file diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index a79a118..56ba324 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -1,9 +1,10 @@ from rest_framework import serializers, exceptions from rest_framework.serializers import ModelSerializer +from apps.em.serializers import EquipmentSimpleSerializer from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse from apps.inm.signals import update_inm from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial -from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer +from apps.mtm.serializers import MaterialSimpleSerializer, RecordFormSimpleSerializer, StepSimpleSerializer from apps.pm.models import SubProductionPlan, SubProductionProgress from django.utils import timezone @@ -11,7 +12,7 @@ from django.utils.translation import gettext_lazy as _ from apps.pm.serializers import SubproductionPlanSimpleSerializer from apps.qm.models import TestRecord, TestRecordItem from apps.system.serializers import UserSimpleSerializer -from apps.wpm.models import Operation, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem +from apps.wpm.models import Operation, OperationEquip, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem from django.db import transaction class PickHalfSerializer(serializers.Serializer): @@ -140,10 +141,22 @@ class OperationDetailSerializer(serializers.ModelSerializer): class OperationListSerializer(serializers.ModelSerializer): create_by_ = UserSimpleSerializer(source='create_by', read_only=True) step_ = StepSimpleSerializer(source='step', read_only=True) + wproduct_count = serializers.SerializerMethodField() + equip_count = serializers.SerializerMethodField() + form_count = serializers.SerializerMethodField() class Meta: model = Operation fields = '__all__' + def get_wproduct_count(self, obj): + return obj.ow_operation.count() + + def get_equip_count(self, obj): + return obj.oe_operation.count() + + def get_form_count(self, obj): + return obj.or_operation.count() + class OperationCreateSerializer(serializers.Serializer): """ 操作创建 @@ -176,6 +189,12 @@ class OperationCreateSerializer(serializers.Serializer): raise exceptions.ValidationError(_('请选择半成品进行操作')) return data + +class OperationUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = OperationRecord + fields =['use_scrap', 'remark'] + class OperationInitSerializer(serializers.Serializer): step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID") subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False) @@ -270,6 +289,23 @@ class WplanPutInSerializer(serializers.Serializer): class WproductPutInSerializer(serializers.Serializer): warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") remark = serializers.CharField(label="入库备注", required =False) + +class OperationEquipListSerializer(serializers.Serializer): + equip_ = EquipmentSimpleSerializer(source='equip', read_only=True) + class Meta: + model = OperationEquip + fields = '__all__' + +class OperationEquipUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = OperationEquip + fields = ['remark'] + +class OperationRecordListSerializer(serializers.ModelSerializer): + form_ = RecordFormSimpleSerializer(source='form', read_only=True) + class Meta: + model = OperationRecord + fields = '__all__' \ No newline at end of file diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index df7aa0d..1113caa 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -1,6 +1,6 @@ from django.shortcuts import render from rest_framework.generics import CreateAPIView, GenericAPIView -from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin +from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin from rest_framework.utils import serializer_helpers from rest_framework.utils.field_mapping import get_relation_kwargs from rest_framework.views import APIView @@ -17,7 +17,7 @@ from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem -from apps.wpm.serializers import OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer +from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationRecordListSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers @@ -259,12 +259,12 @@ class WProductViewSet(ListModelMixin, GenericViewSet): wproduct.save() return Response() -class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, GenericViewSet): +class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, GenericViewSet): """ 生产操作记录 """ perms_map={'*':'*'} - queryset = Operation.objects.select_related('step').all() + queryset = Operation.objects.select_related('step').prefetch_related('ow_operation', 'oe_operation', 'or_operation').all() serializer_class = OperationListSerializer filterset_fields = ['step', 'step__process', 'is_submited'] ordering_fields = ['id'] @@ -278,6 +278,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen return OperationDetailSerializer elif self.action == 'create': return OperationCreateSerializer + elif self.action == 'update': + return OperationUpdateSerializer return super().get_serializer_class() @transaction.atomic @@ -325,7 +327,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen -class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): +class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): """ 操作使用的半成品 """ @@ -346,7 +348,51 @@ class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSe wp.operation = None wp.save() return Response() - + +class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet): + """ + 操作使用的设备 + """ + perms_map={'*':'*'} + queryset = OperationEquip.objects.select_related('operation', 'equip').all() + serializer_class = OperationEquipListSerializer + filterset_fields = ['operation', 'equip'] + ordering_fields = ['id'] + ordering = ['-id'] + + def get_serializer_class(self): + if self.action == 'update': + return OperationEquipUpdateSerializer + return super().get_serializer_class() + @transaction.atomic() + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + instance.delete() + return Response() + +class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): + """ + 操作使用的自定义表格 + """ + perms_map={'*':'*'} + queryset = OperationRecord.objects.select_related('operation', 'form').all() + serializer_class = OperationRecordListSerializer + filterset_fields = ['operation', 'form'] + ordering_fields = ['id'] + ordering = ['-id'] + + @transaction.atomic() + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + instance.delete() + return Response() + + + class DoFormInit(CreateAPIView, GenericAPIView): perms_map={'*':'*'} From dc2468bd71ce83c5cea2a0d4c56aa984ffa60172 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 19 Nov 2021 13:45:57 +0800 Subject: [PATCH 10/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/serializers.py | 2 +- hb_server/apps/wpm/views.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 56ba324..5a755fe 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -192,7 +192,7 @@ class OperationCreateSerializer(serializers.Serializer): class OperationUpdateSerializer(serializers.ModelSerializer): class Meta: - model = OperationRecord + model = Operation fields =['use_scrap', 'remark'] class OperationInitSerializer(serializers.Serializer): diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 1113caa..4662484 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -292,6 +292,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd op = Operation() op.step = step op.is_submited = False + op.create_by = request.user op.save() # 创建操作所用半成品关联记录 if 'wproducts' in vdata: From 28b44f92a8222c492a46ee746838e94aca05dffe Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 19 Nov 2021 13:59:27 +0800 Subject: [PATCH 11/36] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=BD=A6=E9=97=B4?= =?UTF-8?q?=E6=93=8D=E4=BD=9C=E8=AE=BE=E5=A4=87=E3=80=81=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E8=A1=A8=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/serializers.py | 4 ++-- hb_server/apps/wpm/urls.py | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 5a755fe..877ed61 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -143,7 +143,7 @@ class OperationListSerializer(serializers.ModelSerializer): step_ = StepSimpleSerializer(source='step', read_only=True) wproduct_count = serializers.SerializerMethodField() equip_count = serializers.SerializerMethodField() - form_count = serializers.SerializerMethodField() + record_count = serializers.SerializerMethodField() class Meta: model = Operation fields = '__all__' @@ -154,7 +154,7 @@ class OperationListSerializer(serializers.ModelSerializer): def get_equip_count(self, obj): return obj.oe_operation.count() - def get_form_count(self, obj): + def get_record_count(self, obj): return obj.or_operation.count() class OperationCreateSerializer(serializers.Serializer): diff --git a/hb_server/apps/wpm/urls.py b/hb_server/apps/wpm/urls.py index b5d4018..96d2986 100644 --- a/hb_server/apps/wpm/urls.py +++ b/hb_server/apps/wpm/urls.py @@ -3,13 +3,15 @@ from rest_framework import urlpatterns from django.urls import path, include from rest_framework.routers import DefaultRouter -from apps.wpm.views import DoFormInit, DoFormSubmit, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet +from apps.wpm.views import DoFormInit, DoFormSubmit, OperationEquipViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet router = DefaultRouter() router.register('wmaterial', WMaterialViewSet, basename='wmaterial') router.register('wproduct', WProductViewSet, basename='wproduct') router.register('operation', OperationViewSet, basename='operation') router.register('operation_wproduct', OperationWproductViewSet, basename='operation_wproduct') +router.register('operation_equip', OperationEquipViewSet, basename='operation_equip') +router.register('operation_record', OperationRecordViewSet, basename='operation_record') router.register('subplan', WPlanViewSet, basename='wplan') urlpatterns = [ path('do/init/', DoFormInit.as_view()), From 23b75df2d47e16423422e807a005b8ea96a74c13 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sat, 20 Nov 2021 22:23:27 +0800 Subject: [PATCH 12/36] =?UTF-8?q?=E8=87=AA=E5=8A=A8gitpull=20develop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/models.py | 2 +- hb_server/apps/wpm/serializers.py | 7 +++++++ hb_server/apps/wpm/views.py | 23 +++++++++++++++++++++-- hb_server/server/urls.py | 3 ++- hb_server/utils/view.py | 15 +++++++++++++++ 5 files changed, 46 insertions(+), 4 deletions(-) diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index b15585d..517593e 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -80,7 +80,7 @@ class OperationMaterial(BaseModel): type = models.IntegerField('类型', default=0, choices=type_choices) operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE) wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True) - material = models.ForeignKey(Material, verbose_name='可能产出的副产品', on_delete=models.CASCADE, null=True, blank=True) + material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE, null=True, blank=True) count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)]) class OperationRecord(BaseModel): diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 877ed61..cbcdf3d 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -245,6 +245,13 @@ class OperationRecordSerializer(serializers.ModelSerializer): model = OperationRecord fields = ['form', 'record_data'] + +class OperationRecordSubmitSerializer(serializers.ModelSerializer): + record_data = OperationRecordItemSerializer(many=True) + class Meta: + model = OperationRecord + fields = ['record_data'] + class OperationWproductListSerializer(serializers.ModelSerializer): material_ = MaterialSimpleSerializer(source='material', read_only=True) subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 4662484..1cb79c0 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -17,7 +17,7 @@ from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem -from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationRecordListSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer +from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers @@ -392,7 +392,26 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): instance.delete() return Response() - + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=OperationRecordSubmitSerializer) + def submit(self, request, pk=None): + serializer = OperationRecordSubmitSerializer(data=request.data, context={'request':self.request}) + serializer.is_valid(raise_exception=True) + vdata = serializer.data + opr = self.get_object() + wrds = [] + for m in vdata['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'] = opr + wrds.append(OperationRecordItem(**m)) + OperationRecordItem.objects.bulk_create(wrds) + opr.is_filled = True + opr.save() + return Response() class DoFormInit(CreateAPIView, GenericAPIView): diff --git a/hb_server/server/urls.py b/hb_server/server/urls.py index b5ac030..3db8e36 100644 --- a/hb_server/server/urls.py +++ b/hb_server/server/urls.py @@ -26,7 +26,7 @@ from rest_framework.documentation import include_docs_urls from rest_framework_simplejwt.views import (TokenObtainPairView, TokenRefreshView) from django.views.generic import TemplateView -from utils.view import GenSignature +from utils.view import GenSignature, UpdateDevelop router = routers.DefaultRouter() router.register('', FileViewSet, basename="file") @@ -72,6 +72,7 @@ urlpatterns = [ # 工具 path('api/utils/signature/', GenSignature.as_view()), + path('api/utils/develop/', UpdateDevelop.as_view()), # 前端页面入口 path('',TemplateView.as_view(template_name="index.html")) diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py index 23707ff..4c097b9 100644 --- a/hb_server/utils/view.py +++ b/hb_server/utils/view.py @@ -49,3 +49,18 @@ class GenSignature(APIView): image[i][j][0],image[i][j][1],image[i][j][2] = 0,0,0 cv2.imwrite(path,image) return Response(request.data, status=status.HTTP_200_OK) + + +class UpdateDevelop(APIView): + """ + 更新开发服务器 + """ + authentication_classes = () + permission_classes = () + + def post(self, request, *args, **kwargs): + import os + # 更新后端 + os.chdir('/home/hberp') + os.system('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git') + return Response() From 45117b0916fd6eb8770dd755acebc8feb33ba84b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sat, 20 Nov 2021 22:33:15 +0800 Subject: [PATCH 13/36] =?UTF-8?q?=E8=87=AA=E5=8A=A8git=20pull=20=E5=B9=B6?= =?UTF-8?q?=E6=89=93=E5=8C=85=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/utils/view.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py index 4c097b9..478290f 100644 --- a/hb_server/utils/view.py +++ b/hb_server/utils/view.py @@ -63,4 +63,8 @@ class UpdateDevelop(APIView): # 更新后端 os.chdir('/home/hberp') os.system('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git') + # 打包前端 + os.chdir('/home/hberp/hb_client') + os.system('npm run build:prod') + os.system('cp /home/hberp/hb_client/dist/* /home/hberp/hb_server/vuedist') return Response() From 22a540fbd5c5b09c9c220461067353f007d171ac Mon Sep 17 00:00:00 2001 From: caoqianming Date: Sat, 20 Nov 2021 22:48:58 +0800 Subject: [PATCH 14/36] =?UTF-8?q?=E8=87=AA=E5=8A=A8gitpull=E5=B9=B6?= =?UTF-8?q?=E6=89=93=E5=8C=85=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/utils/view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py index 478290f..7f974c4 100644 --- a/hb_server/utils/view.py +++ b/hb_server/utils/view.py @@ -65,6 +65,6 @@ class UpdateDevelop(APIView): os.system('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git') # 打包前端 os.chdir('/home/hberp/hb_client') - os.system('npm run build:prod') + os.system('npm install && npm run build:prod') os.system('cp /home/hberp/hb_client/dist/* /home/hberp/hb_server/vuedist') return Response() From a235b54d2e93c15bd017556160f2c6fb57f51f09 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 00:14:56 +0800 Subject: [PATCH 15/36] =?UTF-8?q?=E5=8F=AA=E6=9B=B4=E6=96=B0=E5=90=8E?= =?UTF-8?q?=E7=AB=AF=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/utils/view.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py index 7f974c4..7fb7136 100644 --- a/hb_server/utils/view.py +++ b/hb_server/utils/view.py @@ -64,7 +64,7 @@ class UpdateDevelop(APIView): os.chdir('/home/hberp') os.system('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git') # 打包前端 - os.chdir('/home/hberp/hb_client') - os.system('npm install && npm run build:prod') - os.system('cp /home/hberp/hb_client/dist/* /home/hberp/hb_server/vuedist') + # os.chdir('/home/hberp/hb_client') + # os.system('npm run build:prod') + # os.system('\cp -rf /home/hberp/hb_client/dist/* /home/hberp/hb_server/vuedist') return Response() From eba134a2c370335f453cbd969361fdb0edafcaae Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 11:03:08 +0800 Subject: [PATCH 16/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E6=B6=88=E8=80=97=E4=BA=A7=E5=87=BA=E5=B7=A5=E5=85=B7=E5=B7=A5?= =?UTF-8?q?=E8=A3=85=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/models.py | 20 +++++----- hb_server/apps/wpm/serializers.py | 39 ++++++++++++++++++- hb_server/apps/wpm/services.py | 23 +++++++++++- hb_server/apps/wpm/urls.py | 5 ++- hb_server/apps/wpm/views.py | 62 ++++++++++++++++++++++++++++++- 5 files changed, 135 insertions(+), 14 deletions(-) diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 517593e..e0d7b62 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -3,11 +3,11 @@ from django.db.models.base import Model import django.utils.timezone as timezone from django.db.models.query import QuerySet from apps.inm.models import WareHouse -from apps.pm.models import ProductionPlan, SubProductionPlan +from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords -from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm +from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial from django.core.validators import MinValueValidator from apps.em.models import Equipment class WMaterial(BaseModel): @@ -42,7 +42,7 @@ class WProduct(CommonAModel): is_hidden = models.BooleanField('是否隐藏', default=False) 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) + 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='关联操作', @@ -73,16 +73,18 @@ class OperationMaterial(BaseModel): """ 生产操作物料消耗产出表 """ - type_choices=( - (1, '消耗'), - (2, '产出') - ) - type = models.IntegerField('类型', default=0, choices=type_choices) + type = models.IntegerField('类型', default=0, choices=SubprodctionMaterial.type_choices) operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE) - wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True) + material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE, null=True, blank=True) count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)]) + wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True) + subproduction_progress = models.ForeignKey(SubProductionProgress, verbose_name='关联的生产进度', on_delete=models.CASCADE, null=True, blank=True) + + subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE, null=True, blank=True) + batch = models.CharField('批次号', max_length=100, null=True, blank=True) + class OperationRecord(BaseModel): """ 记录表格 diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index cbcdf3d..78b0ecc 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -12,7 +12,7 @@ from django.utils.translation import gettext_lazy as _ from apps.pm.serializers import SubproductionPlanSimpleSerializer from apps.qm.models import TestRecord, TestRecordItem from apps.system.serializers import UserSimpleSerializer -from apps.wpm.models import Operation, OperationEquip, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem +from apps.wpm.models import Operation, OperationEquip, OperationMaterial, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem from django.db import transaction class PickHalfSerializer(serializers.Serializer): @@ -313,6 +313,43 @@ class OperationRecordListSerializer(serializers.ModelSerializer): class Meta: model = OperationRecord fields = '__all__' + +class OperationMaterialListSerializer(serializers.ModelSerializer): + material_ = MaterialSimpleSerializer(source='material', read_only=True) + subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True) + class Meta: + model = OperationMaterial + fields = '__all__' + +class OperationMaterialCreate1Serailizer(serializers.ModelSerializer): + wmaterial = serializers.PrimaryKeyRelatedField(required=True, queryset=WMaterial.objects.all()) + 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 + return super().create(validated_data) + +class OperationMaterialCreate2Serailizer(serializers.ModelSerializer): + subproduction_progress = serializers.PrimaryKeyRelatedField(required=True, queryset=SubProductionProgress.objects.all()) + class Meta: + model = OperationMaterial + fields = ['operation', 'subproduction_progress', 'count'] + + def create(self, validated_data): + subproduction_progress = validated_data['subproduction_progress'] + validated_data['material'] = subproduction_progress.material + validated_data['subproduction_plan'] = subproduction_progress.subproduction_plan + return super().create(validated_data) + +class OperationMaterialCreate3Serializer(serializers.ModelSerializer): + material = serializers.PrimaryKeyRelatedField(required=True, queryset=Material.objects.all()) + class Meta: + model = OperationMaterial + fields = ['operation', 'material'] \ No newline at end of file diff --git a/hb_server/apps/wpm/services.py b/hb_server/apps/wpm/services.py index de6e5c8..591914f 100644 --- a/hb_server/apps/wpm/services.py +++ b/hb_server/apps/wpm/services.py @@ -1,5 +1,7 @@ +from typing import List from apps.pm.models import SubProductionPlan -from apps.mtm.models import Step +from apps.mtm.models import Step, SubprodctionMaterial +from apps.wpm.models import WProduct class WpmServies(object): @classmethod @@ -12,4 +14,21 @@ class WpmServies(object): if pindex + 1 < len(stepIds): return Step.objects.get(pk=stepIds[pindex+1]), True else: - return nowstep, False \ No newline at end of file + return nowstep, False + + @classmethod + def get_subplans_queryset_from_wproducts(cls, wproducts:List): + """ + 通过半成品列表获取所属子计划 + """ + splans = SubProductionPlan.objects.filter(is_deleted=False, wproduct__subplan__in=wproducts) + return splans + + @classmethod + def get_subplans_queyset_from_step(cls, step:Step): + """ + 通过当前操作获取所有正在进行的子计划 + """ + splans = SubProductionPlan.objects.filter(is_deleted=False, + subproduction__usedstep_subproduction__step=step, state=SubProductionPlan.SUBPLAN_STATE_WORKING) + return splans \ No newline at end of file diff --git a/hb_server/apps/wpm/urls.py b/hb_server/apps/wpm/urls.py index 96d2986..57db6b9 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 DoFormInit, DoFormSubmit, OperationEquipViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet +from apps.wpm.views import DoFormInit, DoFormSubmit, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet router = DefaultRouter() router.register('wmaterial', WMaterialViewSet, basename='wmaterial') @@ -12,6 +12,9 @@ router.register('operation', OperationViewSet, basename='operation') router.register('operation_wproduct', OperationWproductViewSet, basename='operation_wproduct') router.register('operation_equip', OperationEquipViewSet, basename='operation_equip') router.register('operation_record', OperationRecordViewSet, basename='operation_record') +router.register('operation_input', OperationMaterialInputViewSet, basename='operation_input') +router.register('operation_output', OperationMaterialOutputViewSet, basename='operation_output') +router.register('operation_tool', OperationMaterialToolViewSet, basename='operation_tool') router.register('subplan', WPlanViewSet, basename='wplan') urlpatterns = [ path('do/init/', DoFormInit.as_view()), diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 1cb79c0..4bcf0b0 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -17,7 +17,7 @@ from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem -from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer +from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers @@ -294,9 +294,11 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd op.is_submited = False op.create_by = request.user op.save() + splans = [] # 创建操作所用半成品关联记录 if 'wproducts' in vdata: owps = [] + splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts']) for wpd in vdata['wproducts']: owp = {} owp['operation'] = op @@ -307,6 +309,8 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd owp['production_plan'] = wpd.production_plan owps.append(OperationWproduct(**owp)) OperationWproduct.objects.bulk_create(owps) + else: + splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts']) # 查询需要填写的自定义表格 forms = RecordForm.objects.filter(step=step, type=RecordForm.RF_TYPE_DO) for i in forms: @@ -321,6 +325,14 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd ope.operation = op ope.equip = i ope.save() + # 查询所需的工具工装 + for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL, + subproduction__subplan_subprod__in = splans): + opm = OperationMaterial() + opm.operation = op + opm.material = i.material + opm.type = SubprodctionMaterial.SUB_MA_TYPE_TOOL + opm.save() return Response() @@ -414,6 +426,54 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): return Response() +class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet): + """ + 消耗物料 + """ + perms_map={'*':'*'} + queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN) + serializer_class = OperationMaterialListSerializer + filterset_fields = ['operation', 'subproduction_plan'] + ordering_fields = ['id'] + ordering = ['-id'] + + def get_serializer_class(self): + if self.action == 'create': + return OperationMaterialCreate1Serailizer + return super().get_serializer_class() + +class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet): + """ + 产出物料 + """ + perms_map={'*':'*'} + queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_OUT) + serializer_class = OperationMaterialListSerializer + filterset_fields = ['operation', 'subproduction_plan'] + ordering_fields = ['id'] + ordering = ['-id'] + + def get_serializer_class(self): + if self.action == 'create': + return OperationMaterialCreate2Serailizer + return super().get_serializer_class() + +class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet): + """ + 工具工装 + """ + perms_map={'*':'*'} + queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL) + serializer_class = OperationMaterialListSerializer + filterset_fields = ['operation', 'subproduction_plan'] + ordering_fields = ['id'] + ordering = ['-id'] + + def get_serializer_class(self): + if self.action == 'create': + return OperationMaterialCreate3Serializer + return super().get_serializer_class() + class DoFormInit(CreateAPIView, GenericAPIView): perms_map={'*':'*'} serializer_class=OperationInitSerializer From 684f4b997f5e701835a9f8c71cf1d720ce6df7fd Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 11:11:22 +0800 Subject: [PATCH 17/36] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0019_auto_20211122_1110.py | 46 +++++++++++++++++++ hb_server/apps/wpm/views.py | 2 +- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 hb_server/apps/wpm/migrations/0019_auto_20211122_1110.py diff --git a/hb_server/apps/wpm/migrations/0019_auto_20211122_1110.py b/hb_server/apps/wpm/migrations/0019_auto_20211122_1110.py new file mode 100644 index 0000000..aaffb4a --- /dev/null +++ b/hb_server/apps/wpm/migrations/0019_auto_20211122_1110.py @@ -0,0 +1,46 @@ +# Generated by Django 3.2.9 on 2021-11-22 03:10 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0035_auto_20211117_1637'), + ('pm', '0014_subproductionplan_number'), + ('wpm', '0018_auto_20211119_1340'), + ] + + operations = [ + migrations.AddField( + model_name='operationmaterial', + name='batch', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='批次号'), + ), + migrations.AddField( + model_name='operationmaterial', + name='subproduction_plan', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联的子计划'), + ), + migrations.AddField( + model_name='operationmaterial', + name='subproduction_progress', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionprogress', verbose_name='关联的生产进度'), + ), + migrations.AlterField( + model_name='operationmaterial', + name='material', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='可能产出的产品'), + ), + migrations.AlterField( + model_name='operationmaterial', + name='type', + field=models.IntegerField(choices=[(1, '输入物料'), (2, '输出物料'), (3, '工具工装')], default=0, verbose_name='类型'), + ), + migrations.AlterField( + model_name='wproduct', + name='subproduction_plan', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wproduct_subplan', to='pm.subproductionplan', verbose_name='当前子生产计划'), + ), + ] diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 4bcf0b0..ed9e087 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -327,7 +327,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd ope.save() # 查询所需的工具工装 for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL, - subproduction__subplan_subprod__in = splans): + subproduction__subplan_subprod__in = splans, is_deleted=False).distinct(): opm = OperationMaterial() opm.operation = op opm.material = i.material From d2fb2ffd55bc2d22acfab283c5a9a23209c90934 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 12:58:33 +0800 Subject: [PATCH 18/36] =?UTF-8?q?=E5=88=9B=E5=BB=BAoperation=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/services.py | 2 +- hb_server/apps/wpm/views.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/wpm/services.py b/hb_server/apps/wpm/services.py index 591914f..20f2870 100644 --- a/hb_server/apps/wpm/services.py +++ b/hb_server/apps/wpm/services.py @@ -21,7 +21,7 @@ class WpmServies(object): """ 通过半成品列表获取所属子计划 """ - splans = SubProductionPlan.objects.filter(is_deleted=False, wproduct__subplan__in=wproducts) + splans = SubProductionPlan.objects.filter(is_deleted=False, wproduct_subplan__in=wproducts) return splans @classmethod diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index ed9e087..02c6702 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -259,7 +259,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): wproduct.save() return Response() -class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, GenericViewSet): +class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet): """ 生产操作记录 """ From 5601834a3312bcba9f96620a8fd0b14851d5a88f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 13:04:49 +0800 Subject: [PATCH 19/36] utils develop --- hb_server/utils/view.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py index 7fb7136..1fc57d1 100644 --- a/hb_server/utils/view.py +++ b/hb_server/utils/view.py @@ -62,9 +62,9 @@ class UpdateDevelop(APIView): import os # 更新后端 os.chdir('/home/hberp') - os.system('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git') + ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git') # 打包前端 # os.chdir('/home/hberp/hb_client') # os.system('npm run build:prod') # os.system('\cp -rf /home/hberp/hb_client/dist/* /home/hberp/hb_server/vuedist') - return Response() + return Response(ret.read()) From 4be153762515962df0054bd7ffc7797c6aff3938 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 13:56:24 +0800 Subject: [PATCH 20/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9C?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/filters.py | 17 +++++++++++++++++ hb_server/apps/wpm/models.py | 2 +- hb_server/apps/wpm/views.py | 10 +++++++++- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 hb_server/apps/wpm/filters.py diff --git a/hb_server/apps/wpm/filters.py b/hb_server/apps/wpm/filters.py new file mode 100644 index 0000000..f14d741 --- /dev/null +++ b/hb_server/apps/wpm/filters.py @@ -0,0 +1,17 @@ +from django_filters import rest_framework as filters +from .models import Operation, WMaterial, WProduct + +class WMaterialFilterSet(filters.FilterSet): + + operation = filters.NumberFilter(method='filter_operation') + class Meta: + model = WMaterial + fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop'] + + def filter_operation(self, queryset, name, value): + operation = Operation.objects.get(pk=value) + wproducts = WProduct.objects.filter(ow_wproduct__operation=value) + if wproducts.exists(): + pass + else: + pass \ No newline at end of file diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index e0d7b62..f2d3f5f 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -62,7 +62,7 @@ class OperationWproduct(BaseModel): 生产操作半成品关联表 """ operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='ow_operation') - wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE) + wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='ow_wproduct') 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) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 02c6702..bc1b8b7 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -15,6 +15,7 @@ from apps.qm.models import TestRecordItem from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action +from apps.wpm.filters import WMaterialFilterSet from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer @@ -25,6 +26,7 @@ from rest_framework import exceptions, serializers from apps.wpm.services import WpmServies from django.utils import timezone from utils.tools import ranstr +from rest_framework import status # Create your views here. class WPlanViewSet(ListModelMixin, GenericViewSet): """ @@ -137,7 +139,7 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet): perms_map={'*':'*'} queryset = WMaterial.objects.select_related('material').all() serializer_class = WMaterialListSerializer - filterset_fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop'] + filterset_class = WMaterialFilterSet ordering_fields = ['material__number'] ordering = ['material__number'] @@ -282,6 +284,12 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd return OperationUpdateSerializer return super().get_serializer_class() + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if instance.is_submited: + raise exceptions.APIException('该操作已提交') + self.perform_destroy(instance) + return Response(status=status.HTTP_204_NO_CONTENT) @transaction.atomic def create(self, request, *args, **kwargs): data = request.data From 40a3c5f1898fdc66c0b8b1f6d04ba07f9263e103 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 13:58:51 +0800 Subject: [PATCH 21/36] =?UTF-8?q?=E6=9B=B4=E6=96=B0develop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/utils/view.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py index 1fc57d1..07d1c30 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') + ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git origin develop') # 打包前端 # os.chdir('/home/hberp/hb_client') # os.system('npm run build:prod') From b609a72408af45cb2924d13bf2589a54003eab8c Mon Sep 17 00:00:00 2001 From: shijing Date: Mon, 22 Nov 2021 14:05:37 +0800 Subject: [PATCH 22/36] customForm --- hb_client/src/views/mtm/materialdo.vue | 980 ++++++++++++++----------- 1 file changed, 564 insertions(+), 416 deletions(-) diff --git a/hb_client/src/views/mtm/materialdo.vue b/hb_client/src/views/mtm/materialdo.vue index 2795f0d..cb20e7a 100644 --- a/hb_client/src/views/mtm/materialdo.vue +++ b/hb_client/src/views/mtm/materialdo.vue @@ -2,27 +2,34 @@
+ -
- 物料检验记录表 -
- 新增 + 物料检验记录表 +
+ + 新增 + + - + @@ -31,22 +38,26 @@ 查看查看 + 编辑编辑 + 删除删除 + + - +
取消 + >取消 + 确认 + >确认 +
+ - + - - + + @@ -124,11 +140,12 @@ :label="item.field_name" > @@ -137,9 +154,10 @@ :label="item.field_name" > @@ -178,6 +196,7 @@ +
@@ -187,8 +206,10 @@ type="primary" icon="el-icon-plus" @click="handlefieldCreate" - >新增新增 + + - + + }} + + }} + + }} + - + - + - + + + - - - - - - + !--> + + @@ -424,10 +446,12 @@
取消取消 + 确认确认 +
@@ -439,329 +463,453 @@ From d58f97c00360ca64ec9b3d1a48724e0dc8a037be Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 14:37:31 +0800 Subject: [PATCH 23/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E7=89=A9=E6=96=99/?= =?UTF-8?q?=E5=AD=90=E8=AE=A1=E5=88=92=E8=BF=9B=E5=BA=A6=E6=8C=89operation?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/pm/filters.py | 22 ++++++++++++++++++++++ hb_server/apps/pm/urls.py | 3 ++- hb_server/apps/pm/views.py | 15 ++++++++++++++- hb_server/apps/wpm/filters.py | 9 ++++++--- hb_server/apps/wpm/views.py | 8 ++++++-- 5 files changed, 50 insertions(+), 7 deletions(-) create mode 100644 hb_server/apps/pm/filters.py diff --git a/hb_server/apps/pm/filters.py b/hb_server/apps/pm/filters.py new file mode 100644 index 0000000..d025611 --- /dev/null +++ b/hb_server/apps/pm/filters.py @@ -0,0 +1,22 @@ +from django_filters import rest_framework as filters +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) + if wproducts.exists(): + subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts) + else: + subplans = WpmServies.get_subplans_queyset_from_step(operation.step) + return queryset.filter(subproduction_plan__in=subplans) \ No newline at end of file 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..6f96092 100644 --- a/hb_server/apps/wpm/filters.py +++ b/hb_server/apps/wpm/filters.py @@ -1,4 +1,6 @@ from django_filters import rest_framework as filters + +from apps.wpm.services import WpmServies from .models import Operation, WMaterial, WProduct class WMaterialFilterSet(filters.FilterSet): @@ -6,12 +8,13 @@ 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) 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(operation.step) + return queryset.filter(subproduction_plan__in=subplans) \ No newline at end of file diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index bc1b8b7..6967399 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -343,8 +343,12 @@ 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): + """ + 提交车间操作重要 + """ From 0238e09d0ace6b4b0bf486a449d39685480cb248 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 14:59:45 +0800 Subject: [PATCH 24/36] wmaterial filterset --- hb_server/apps/wpm/filters.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/wpm/filters.py b/hb_server/apps/wpm/filters.py index 6f96092..f11be8b 100644 --- a/hb_server/apps/wpm/filters.py +++ b/hb_server/apps/wpm/filters.py @@ -1,4 +1,5 @@ from django_filters import rest_framework as filters +from apps.mtm.models import Step from apps.wpm.services import WpmServies from .models import Operation, WMaterial, WProduct @@ -13,8 +14,12 @@ class WMaterialFilterSet(filters.FilterSet): 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(operation.step) - return queryset.filter(subproduction_plan__in=subplans) \ No newline at end of file + subplans = WpmServies.get_subplans_queyset_from_step(step) + queryset = queryset.filter(subproduction_plan__in=subplans) + # if step.type == Step.STEP_TYPE_NOM: + # queryset = queryset.filter() + return queryset \ No newline at end of file From 8666c13da8f810242ca8185aa32ebdec234bb932 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 22 Nov 2021 16:13:36 +0800 Subject: [PATCH 25/36] =?UTF-8?q?=E6=B6=88=E8=80=97=E4=BA=A7=E5=87=BA?= =?UTF-8?q?=E7=89=A9=E6=96=99=E6=8E=A5=E5=8F=A3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/pm/filters.py | 9 ++++++-- .../pm/migrations/0015_auto_20211122_1556.py | 23 +++++++++++++++++++ hb_server/apps/pm/models.py | 2 ++ hb_server/apps/wpm/filters.py | 6 ++--- .../0020_alter_operationwproduct_wproduct.py | 19 +++++++++++++++ hb_server/apps/wpm/serializers.py | 8 ++++++- hb_server/apps/wpm/views.py | 13 +++++++++++ 7 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 hb_server/apps/pm/migrations/0015_auto_20211122_1556.py create mode 100644 hb_server/apps/wpm/migrations/0020_alter_operationwproduct_wproduct.py diff --git a/hb_server/apps/pm/filters.py b/hb_server/apps/pm/filters.py index d025611..313c63d 100644 --- a/hb_server/apps/pm/filters.py +++ b/hb_server/apps/pm/filters.py @@ -1,4 +1,5 @@ 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 @@ -15,8 +16,12 @@ class SubproductionProgressFilterSet(filters.FilterSet): 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(operation.step) - return queryset.filter(subproduction_plan__in=subplans) \ No newline at end of file + 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/wpm/filters.py b/hb_server/apps/wpm/filters.py index f11be8b..eac725e 100644 --- a/hb_server/apps/wpm/filters.py +++ b/hb_server/apps/wpm/filters.py @@ -1,5 +1,5 @@ from django_filters import rest_framework as filters -from apps.mtm.models import Step +from apps.mtm.models import Material, Step from apps.wpm.services import WpmServies from .models import Operation, WMaterial, WProduct @@ -19,7 +19,5 @@ class WMaterialFilterSet(filters.FilterSet): 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.filter() + 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/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 6967399..3c8e00d 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -349,6 +349,19 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd """ 提交车间操作重要 """ + op = self.get_object() + # 更新物料消耗进度 + 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() + # 更新物料产出情况 + From a0e56d3666f5dafc5a50f4cf1c88c9836de0fe08 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 23 Nov 2021 09:46:25 +0800 Subject: [PATCH 26/36] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=93=8D=E4=BD=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0021_auto_20211123_0945.py | 21 +++++ hb_server/apps/wpm/models.py | 2 - hb_server/apps/wpm/views.py | 86 ++++++++++++++++--- hb_server/utils/view.py | 2 +- 4 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 hb_server/apps/wpm/migrations/0021_auto_20211123_0945.py 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/views.py b/hb_server/apps/wpm/views.py index 3c8e00d..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: @@ -350,6 +349,10 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd 提交车间操作重要 """ 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): # 更新车间物料 @@ -360,9 +363,69 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd 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): @@ -598,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) @@ -628,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: @@ -658,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') From 07750baa99e65a7352a3c9aca4f67c7754369e7d Mon Sep 17 00:00:00 2001 From: shijing Date: Tue, 23 Nov 2021 10:01:06 +0800 Subject: [PATCH 27/36] glassPicture --- hb_client/src/assets/glass.png | Bin 0 -> 15383 bytes hb_client/src/views/mtm/materialdo.vue | 335 +++++++++++++++++++++++-- 2 files changed, 317 insertions(+), 18 deletions(-) create mode 100644 hb_client/src/assets/glass.png diff --git a/hb_client/src/assets/glass.png b/hb_client/src/assets/glass.png new file mode 100644 index 0000000000000000000000000000000000000000..7b7c511e1e44eb02218a1183db2446d6f7b0f14f GIT binary patch literal 15383 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 literal 0 HcmV?d00001 diff --git a/hb_client/src/views/mtm/materialdo.vue b/hb_client/src/views/mtm/materialdo.vue index cb20e7a..029abea 100644 --- a/hb_client/src/views/mtm/materialdo.vue +++ b/hb_client/src/views/mtm/materialdo.vue @@ -87,11 +87,38 @@ :title="tableForm.name" > + + + +
+ +
+ + 您的浏览器不支持绘图,请升级或更换浏览器! + + + + +
+
标记
+
文字
+ +
回退
+
保存
+ +
+
+
+
+
+ +
+
- - - - @@ -200,7 +223,7 @@
- 记录字段 + 记录字段
!--> - + - + + + + + + { + that.tableForm = Object.assign({}, scope.row); // copy obj + that.formID = that.tableForm.id; + that.listQueryfield.form = that.formID; + getrffieldList(that.listQueryfield).then((response) => { if (response.data) { debugger; - this.fieldList = response.data; + that.fieldList = response.data; let list = response.data.results; for(let i=0;icanvasWidth-oldX){ + ctx3.fillText(v.substring(lastSubStrIndex,i),oldX,(oldY+10)); + oldY+=20; + lineWidth=0; + lastSubStrIndex=i; + } + if(i==v.length-1){ + ctx3.fillText(v.substring(lastSubStrIndex,i+1),oldX,(oldY+10)); + } + } + inputV ="2"; + word3.value = ""; + } + } + } + } + }, + + // 文字过长超出换行toDataURL() + canvasTextAutoLine(str,canvas,initX,initY,lineHeight){ + let ctx = canvas.getContext("2d"); + let lineWidth = 0; + let canvasWidth = canvas.width; + let lastSubStrIndex= 0; + for(let i=0;icanvasWidth-initX){ + ctx.fillText(str.substring(lastSubStrIndex,i),initX,initY); + initY+=lineHeight; + lineWidth=0; + lastSubStrIndex=i; + } + if(i==str.length-1){ + ctx.fillText(str.substring(lastSubStrIndex,i+1),initX,initY); + } + } + }, + + /* // 删除批注 + restuya(){ + this.word.style.display="none"; + this.Txt.style.display="none"; + this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height); + window.location.reload(); + },*/ + + // 撤销 + back(){ + this.word.style.display="none"; + this.Txt.style.display="none"; + if(preDrawAry.length>0) { + var popData = preDrawAry.pop(); + this.ctx.putImageData(popData, 0, 0); + } + }, + + // 回退一次 + put(){ + this.ctx.putImageData(this.imgData,0,0); + }, + + //保存 + saveTu(){ + let canvas = document.getElementById('canvas'); + let image = new Image(); + image = canvas.toDataURL('image/png'); + this.canvasImg = image; + // document.getElementById('res').innerHTML = ''; + }, + + //新增记录表 handleCreate() { this.recordform = Object.assign({}, defaultrecordform); @@ -912,4 +1160,55 @@ .my-content { background: #fde2e2; } + canvas{ + border:1px solid #000000; + cursor: crosshair; + } + .canvasBtnWrap{ + display: flex; + flex-direction: column; + width: 80px; + padding-left: 20px; + justify-content: space-between; + } + .canvasBtn{ + width: 70px; + height: 35px; + line-height: 35px; + border: 1px solid #aaaaaa; + text-align: center; + border-radius: 15px; + } + .hide{ + display: none; + } + #txt{ + position: absolute; + top: 1%; + left: 1%; + width: 150px; + height: 30px; + border:1px solid #e42343; + } + #word{ + position: absolute; + width: 150px; + height: 70px; + padding: 0 2px; + background:none; + color:#e42343; + border: 1px dashed #b9b9b9; + } + #word::-webkit-input-placeholder{ + color:#e42343; + } + #word::-moz-placeholder{ + color:#e42343; + } + #word::placeholder{ + color:#e42343; + } + #res{ + display: inline-block; + } From d44d123d48b7a70fda58d7af0a3fcef865a188f1 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 23 Nov 2021 10:29:33 +0800 Subject: [PATCH 28/36] =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=8F=90=E4=BA=A4bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/serializers.py | 15 ++++---- hb_server/apps/wpm/views.py | 60 +++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 10 deletions(-) diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 3b87574..ed2850a 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -3,7 +3,7 @@ from rest_framework.serializers import ModelSerializer from apps.em.serializers import EquipmentSimpleSerializer from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse from apps.inm.signals import update_inm -from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial +from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial from apps.mtm.serializers import MaterialSimpleSerializer, RecordFormSimpleSerializer, StepSimpleSerializer from apps.pm.models import SubProductionPlan, SubProductionProgress @@ -239,19 +239,18 @@ class OperationRecordItemSerializer(serializers.ModelSerializer): model = OperationRecordItem fields = ['form_field', 'field_value'] -class OperationRecordSerializer(serializers.ModelSerializer): - record_data = OperationRecordItemSerializer(many=True) - class Meta: - model = OperationRecord - fields = ['form', 'record_data'] - - class OperationRecordSubmitSerializer(serializers.ModelSerializer): record_data = OperationRecordItemSerializer(many=True) class Meta: model = OperationRecord fields = ['record_data'] +class OperationRecordSerializer(serializers.ModelSerializer): + record_data = OperationRecordItemSerializer(many=True) + class Meta: + model = OperationRecord + fields = ['form', 'record_data'] + class OperationWproductListSerializer(serializers.ModelSerializer): material_ = MaterialSimpleSerializer(source='material', read_only=True) subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index c0fc856..84b0dbd 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -7,7 +7,7 @@ from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet, ModelViewSet from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse from apps.inm.signals import update_inm -from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial, TechDoc +from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer @@ -284,12 +284,19 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd return OperationUpdateSerializer return super().get_serializer_class() + def update(self, request, *args, **kwargs): + instance = self.get_object() + if instance.is_submited: + raise exceptions.APIException('该操作已提交') + return super().update(request, *args, **kwargs) + def destroy(self, request, *args, **kwargs): instance = self.get_object() if instance.is_submited: raise exceptions.APIException('该操作已提交') self.perform_destroy(instance) return Response(status=status.HTTP_204_NO_CONTENT) + @transaction.atomic def create(self, request, *args, **kwargs): data = request.data @@ -465,6 +472,13 @@ class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, if self.action == 'update': return OperationEquipUpdateSerializer return super().get_serializer_class() + + def update(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + return super().update(request, *args, **kwargs) + @transaction.atomic() def destroy(self, request, *args, **kwargs): instance = self.get_object() @@ -500,7 +514,7 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): opr = self.get_object() wrds = [] for m in vdata['record_data']: # 保存记录详情 - form_field = m['form_field'] + form_field = RecordFormField.objects.get(pk=m['form_field']) m['field_name'] = form_field.field_name m['field_key'] = form_field.field_key m['field_type'] = form_field.field_type @@ -529,6 +543,20 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod if self.action == 'create': return OperationMaterialCreate1Serailizer return super().get_serializer_class() + + def create(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + return super().create(request, *args, **kwargs) + + @transaction.atomic() + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + instance.delete() + return Response() class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet): """ @@ -545,6 +573,20 @@ class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyMo if self.action == 'create': return OperationMaterialCreate2Serailizer return super().get_serializer_class() + + def create(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + return super().create(request, *args, **kwargs) + + @transaction.atomic() + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + instance.delete() + return Response() class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet): """ @@ -562,6 +604,20 @@ class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyMode return OperationMaterialCreate3Serializer return super().get_serializer_class() + def create(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + return super().create(request, *args, **kwargs) + + @transaction.atomic() + def destroy(self, request, *args, **kwargs): + instance = self.get_object() + if instance.operation.is_submited: + raise exceptions.APIException('该操作已提交') + instance.delete() + return Response() + class DoFormInit(CreateAPIView, GenericAPIView): perms_map={'*':'*'} serializer_class=OperationInitSerializer From 048e25311e35aaf93723de4adc9e507cc58ce73a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 23 Nov 2021 10:56:01 +0800 Subject: [PATCH 29/36] =?UTF-8?q?=E5=A1=AB=E5=86=99=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E6=8F=90=E4=BA=A4bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mtm/migrations/0036_auto_20211123_1052.py | 23 +++++++++++++++++++ hb_server/apps/mtm/models.py | 3 +++ hb_server/apps/wpm/views.py | 3 ++- 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 hb_server/apps/mtm/migrations/0036_auto_20211123_1052.py diff --git a/hb_server/apps/mtm/migrations/0036_auto_20211123_1052.py b/hb_server/apps/mtm/migrations/0036_auto_20211123_1052.py new file mode 100644 index 0000000..c0e36de --- /dev/null +++ b/hb_server/apps/mtm/migrations/0036_auto_20211123_1052.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.9 on 2021-11-23 02:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0035_auto_20211117_1637'), + ] + + operations = [ + migrations.AddField( + model_name='recordformfield', + name='draw_template', + field=models.CharField(blank=True, max_length=200, null=True, verbose_name='绘图模板'), + ), + migrations.AlterField( + model_name='recordformfield', + name='field_type', + field=models.CharField(choices=[('string', '字符串'), ('int', '整型'), ('float', '浮点'), ('boolean', '布尔'), ('date', '日期'), ('time', '时间'), ('datetime', '日期时间'), ('radio', '单选'), ('checkbox', '多选'), ('select', '单选下拉'), ('selects', '多选下拉'), ('textarea', '文本域'), ('draw', '绘图')], max_length=50, verbose_name='类型'), + ), + ] diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index 46e82b4..c6ebc6e 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -131,6 +131,7 @@ class RecordFormField(CommonAModel): ('select', '单选下拉'), ('selects', '多选下拉'), ('textarea', '文本域'), + ('draw', '绘图') ) high_rule_choices = ( (1, '小于'), @@ -161,6 +162,8 @@ class RecordFormField(CommonAModel): is_hidden = models.BooleanField('是否隐藏', default=False) parent = models.ForeignKey('self', verbose_name='父', on_delete=models.CASCADE, null=True, blank=True) + draw_template = models.CharField('绘图模板', max_length=200, null=True, blank=True) + class Meta: verbose_name = '记录表格字段' diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 84b0dbd..2b2a75f 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -514,7 +514,8 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): opr = self.get_object() wrds = [] for m in vdata['record_data']: # 保存记录详情 - form_field = RecordFormField.objects.get(pk=m['form_field']) + form_field = RecordFormField.objects.get(pk=m['form_field']) + m['form_field'] = form_field m['field_name'] = form_field.field_name m['field_key'] = form_field.field_key m['field_type'] = form_field.field_type From 995649ad25ce47d1d6f40744b367ebb0f75ea1ae Mon Sep 17 00:00:00 2001 From: shijing Date: Tue, 23 Nov 2021 13:59:09 +0800 Subject: [PATCH 30/36] glassPicture --- hb_client/src/api/file.js | 9 ++- hb_client/src/views/mtm/materialdo.vue | 76 ++++++++++++++------------ 2 files changed, 49 insertions(+), 36 deletions(-) diff --git a/hb_client/src/api/file.js b/hb_client/src/api/file.js index 01c683e..9ad01c7 100644 --- a/hb_client/src/api/file.js +++ b/hb_client/src/api/file.js @@ -15,4 +15,11 @@ export function getFileList(query) { method: 'get', params: query }) -} \ No newline at end of file +} +export function upFile(data) { + return request({ + url: '/file/', + method: 'post', + data + }) +} diff --git a/hb_client/src/views/mtm/materialdo.vue b/hb_client/src/views/mtm/materialdo.vue index 029abea..421edae 100644 --- a/hb_client/src/views/mtm/materialdo.vue +++ b/hb_client/src/views/mtm/materialdo.vue @@ -87,32 +87,6 @@ :title="tableForm.name" > - - - -
- -
- - 您的浏览器不支持绘图,请升级或更换浏览器! - - - - -
-
标记
-
文字
- -
回退
-
保存
- -
-
-
-
-
- -
+ +
+ +
+ + 您的浏览器不支持绘图,请升级或更换浏览器! + + + + +
+
标记
+
文字
+ +
回退
+
保存
+
+
+
+
+
@@ -458,7 +453,7 @@ - + - + @@ -513,6 +508,7 @@ updaterffield, deleterffield, } from "@/api/mtm"; + import { upFile } from "@/api/file"; import {genTree} from "@/utils"; import Pagination from "@/components/Pagination"; // secondary package based on el-pagination import Treeselect from '@riophae/vue-treeselect' @@ -546,7 +542,7 @@ field_name: "", sort: "", parent: "", - TempPicture: "", + draw_template: "",//图片模板 field_choice: [""], }, field_choice: [""], @@ -604,7 +600,7 @@ datetime: "日期时间", select: "单选", selects: "多选", - img: "图片", + draw: "绘图模板", }, fieldtypeoptions: [ { @@ -640,8 +636,8 @@ label: "多选", }, { - value: "img", - label: "图片", + value: "draw", + label: "绘图模板", }, ], typeoptions: [ @@ -671,8 +667,7 @@ }, methods: { handleAvatarSuccess(res, file) { - this.field.TempPicture = res.data.path; - + this.field.draw_template = res.data.path; }, beforeAvatarUpload(file) { const isLt2M = file.size / 1024 / 1024 < 2; @@ -1012,10 +1007,21 @@ let image = new Image(); image = canvas.toDataURL('image/png'); this.canvasImg = image; + let img = image.split(";")[1]; + debugger; + console.log(image); + debugger; + let imgData = {mime:'base64',file:img,type:'图片'}; + upFile(imgData).then((res) => { + debugger; + console.log(res); + debugger; + }) + + // document.getElementById('res').innerHTML = ''; }, - //新增记录表 handleCreate() { this.recordform = Object.assign({}, defaultrecordform); From 7dcdcfa79761dbc627f3e6f0102e05810587cd45 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 23 Nov 2021 14:26:07 +0800 Subject: [PATCH 31/36] =?UTF-8?q?=E6=93=8D=E4=BD=9C=E6=8F=90=E4=BA=A4bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wpm/migrations/0022_auto_20211123_1425.py | 23 +++++++++++++++++++ hb_server/apps/wpm/models.py | 2 +- hb_server/apps/wpm/views.py | 19 ++++++++------- 3 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 hb_server/apps/wpm/migrations/0022_auto_20211123_1425.py diff --git a/hb_server/apps/wpm/migrations/0022_auto_20211123_1425.py b/hb_server/apps/wpm/migrations/0022_auto_20211123_1425.py new file mode 100644 index 0000000..bf6b8de --- /dev/null +++ b/hb_server/apps/wpm/migrations/0022_auto_20211123_1425.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.9 on 2021-11-23 06:25 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0021_auto_20211123_0945'), + ] + + operations = [ + migrations.RemoveField( + model_name='wproduct', + name='parent', + ), + migrations.AddField( + model_name='wproduct', + name='child', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct'), + ), + ] diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index ee835a1..db98eab 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -40,7 +40,7 @@ class WProduct(CommonAModel): act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices) is_executed = models.BooleanField('子工序是否已执行', default=False) is_hidden = models.BooleanField('是否隐藏', default=False) - parent = models.JSONField('父', default=list, blank=True) + child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE) 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') warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 2b2a75f..e200b2d 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -364,23 +364,22 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd 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.count = i_wmat.count- i.count i_wmat.save() # 更新子计划物料消耗情况 sp = i_wmat.subproduction_plan - sp.count_real = sp.count_real + i['count'] + 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, _ = 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.count_real = sp.count_real + i.count sp.save() # 更新动态产品表 if step.type == Step.STEP_TYPE_NOM: @@ -417,21 +416,25 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd 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 + # 更新子计划进度 + instance = SubProductionProgress.objects.get(subproduction_plan=i.subproduction_plan, + is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) + instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨 + instance.save() wproduct.save() + ows.update(is_hidden=True, child=wproduct) From fd2141598e3c5536b5c2449157f80a0a084e1126 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 23 Nov 2021 14:37:11 +0800 Subject: [PATCH 32/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9Cbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index e200b2d..26d81e2 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -367,9 +367,10 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd 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() + spp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan, + material=i_wmat.material) + spp.count_real = spp.count_real + i.count + spp.save() # 更新产出 for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT): if not i.subproduction_progress.is_main: @@ -378,9 +379,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd ins.count = ins.count + i.count ins.save() # 更新子计划物料产出情况 - sp = i.subproduction_progress - sp.count_real = sp.count_real + i.count - sp.save() + spp = i.subproduction_progress + spp.count_real = spp.count_real + i.count + spp.save() # 更新动态产品表 if step.type == Step.STEP_TYPE_NOM: for i in OperationWproduct.objects.filter(operation=op): @@ -435,6 +436,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd instance.save() wproduct.save() ows.update(is_hidden=True, child=wproduct) + op.is_submited = True + op.save() + return Response() From 32018645caceb436a77c14624184e058739b6f8e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 23 Nov 2021 14:41:25 +0800 Subject: [PATCH 33/36] =?UTF-8?q?=E8=BD=A6=E9=97=B4=E6=93=8D=E4=BD=9Cbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 26d81e2..927ab17 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -551,12 +551,6 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod if self.action == 'create': return OperationMaterialCreate1Serailizer return super().get_serializer_class() - - def create(self, request, *args, **kwargs): - instance = self.get_object() - if instance.operation.is_submited: - raise exceptions.APIException('该操作已提交') - return super().create(request, *args, **kwargs) @transaction.atomic() def destroy(self, request, *args, **kwargs): @@ -581,12 +575,6 @@ class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyMo if self.action == 'create': return OperationMaterialCreate2Serailizer return super().get_serializer_class() - - def create(self, request, *args, **kwargs): - instance = self.get_object() - if instance.operation.is_submited: - raise exceptions.APIException('该操作已提交') - return super().create(request, *args, **kwargs) @transaction.atomic() def destroy(self, request, *args, **kwargs): @@ -611,12 +599,6 @@ class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyMode if self.action == 'create': return OperationMaterialCreate3Serializer return super().get_serializer_class() - - def create(self, request, *args, **kwargs): - instance = self.get_object() - if instance.operation.is_submited: - raise exceptions.APIException('该操作已提交') - return super().create(request, *args, **kwargs) @transaction.atomic() def destroy(self, request, *args, **kwargs): From 647486b959a68297f73ac46182e0ad4664403f12 Mon Sep 17 00:00:00 2001 From: shijing Date: Tue, 23 Nov 2021 14:57:41 +0800 Subject: [PATCH 34/36] picture --- hb_client/src/views/mtm/materialdo.vue | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/hb_client/src/views/mtm/materialdo.vue b/hb_client/src/views/mtm/materialdo.vue index 421edae..af831ea 100644 --- a/hb_client/src/views/mtm/materialdo.vue +++ b/hb_client/src/views/mtm/materialdo.vue @@ -1007,19 +1007,25 @@ let image = new Image(); image = canvas.toDataURL('image/png'); this.canvasImg = image; - let img = image.split(";")[1]; - debugger; - console.log(image); - debugger; - let imgData = {mime:'base64',file:img,type:'图片'}; - upFile(imgData).then((res) => { + let file = this.base64ToFile(image); + let formData = new FormData(); + formData.append('file', file); + upFile(formData).then((res) => { debugger; console.log(res); debugger; }) - - - // document.getElementById('res').innerHTML = ''; + }, + base64ToFile(baseUrl) { + let arr = baseUrl.split(','); + // let type = arr[0].match(/:(.*?);/)[1]; // 解锁图片类型 + let bytes = atob(arr[1]); // 解码base64 + let n = bytes .length; + let bufferArray = new Uint8Array(n); + while (n--) { + bufferArray[n] = bytes.charCodeAt(n); + } + return new File([bufferArray ],{ type:'image/png'}); }, //新增记录表 From eb6a7607f3d944805732c76ac9480bd4ce193f20 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 23 Nov 2021 14:58:10 +0800 Subject: [PATCH 35/36] =?UTF-8?q?operation=20list=20=E6=8E=A5=E5=8F=A3bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 927ab17..cdb81de 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -158,7 +158,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): 半成品 """ perms_map={'*':'*'} - queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False).exclude(operation=None) + queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False, operation=None) serializer_class = WProductListSerializer filterset_fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state'] search_fields = ['number'] From 321b81931211a789b7cd990e66331255e1e300c5 Mon Sep 17 00:00:00 2001 From: shijing Date: Tue, 23 Nov 2021 15:19:40 +0800 Subject: [PATCH 36/36] picture --- hb_client/src/views/mtm/materialdo.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hb_client/src/views/mtm/materialdo.vue b/hb_client/src/views/mtm/materialdo.vue index af831ea..317fcf4 100644 --- a/hb_client/src/views/mtm/materialdo.vue +++ b/hb_client/src/views/mtm/materialdo.vue @@ -1025,7 +1025,8 @@ while (n--) { bufferArray[n] = bytes.charCodeAt(n); } - return new File([bufferArray ],{ type:'image/png'}); + // let fileOfBlob = new File([bufferArray], new Date()+'.jpg'); + return new File([bufferArray ],'draw.jpg'); }, //新增记录表