From 87eb8f1f1cdd9ca6fb91bad61674433b76ea0120 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 13 Dec 2021 13:50:14 +0800 Subject: [PATCH 01/20] =?UTF-8?q?=E5=A2=9E=E5=8A=A0iproduct=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E6=9D=A1=E4=BB=B6/=E7=94=98=E7=89=B9=E5=9B=BEplan?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/filters.py | 2 +- hb_server/apps/pm/models.py | 9 ++++++++- hb_server/apps/srm/serializers.py | 22 ++++++++++++++++++++++ hb_server/apps/srm/urls.py | 13 +++++++++++++ hb_server/apps/srm/views.py | 15 ++++++++++++--- hb_server/server/urls.py | 2 +- 6 files changed, 57 insertions(+), 6 deletions(-) create mode 100644 hb_server/apps/srm/serializers.py create mode 100644 hb_server/apps/srm/urls.py diff --git a/hb_server/apps/inm/filters.py b/hb_server/apps/inm/filters.py index 2ff12aa..09f8777 100644 --- a/hb_server/apps/inm/filters.py +++ b/hb_server/apps/inm/filters.py @@ -14,4 +14,4 @@ class IProductFilterSet(filters.FilterSet): order = filters.NumberFilter(field_name="wproduct__subproduction_plan__production_plan__order") class Meta: model = IProduct - fields = ['material', 'warehouse', 'batch', 'order', 'is_mtested', 'is_mtestok'] \ No newline at end of file + fields = ['material', 'warehouse', 'batch', 'order', 'is_mtested', 'is_mtestok', 'material__type'] \ No newline at end of file diff --git a/hb_server/apps/pm/models.py b/hb_server/apps/pm/models.py index 6a06c29..346428f 100644 --- a/hb_server/apps/pm/models.py +++ b/hb_server/apps/pm/models.py @@ -14,6 +14,13 @@ class ProductionPlan(CommonAModel): """ 生产计划 """ + # PLAN_STATE_WAIT = 6 + # PLAN_STATE_WORKING = 10 + # PLAN_STATE_DONE = 20 + # state_choices = ( + # (PLAN_STATE_WORKING, '进行中'), + # (PLAN_STATE_DONE, '已完成') + # ) number = models.CharField('编号', max_length=50, unique=True) order = models.ForeignKey(Order, verbose_name='关联订单', null=True, blank=True, on_delete=models.SET_NULL) product = models.ForeignKey(Material, verbose_name='生产产品', on_delete=models.CASCADE) @@ -47,7 +54,7 @@ class SubProductionPlan(CommonAModel): (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) + production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE, related_name='subplan_plan') subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subplan_subprod') start_date = models.DateField('计划开工日期') end_date = models.DateField('计划完工日期') diff --git a/hb_server/apps/srm/serializers.py b/hb_server/apps/srm/serializers.py new file mode 100644 index 0000000..a142348 --- /dev/null +++ b/hb_server/apps/srm/serializers.py @@ -0,0 +1,22 @@ +from rest_framework import serializers +from apps.pm.models import ProductionPlan, SubProductionPlan +from apps.mtm.serializers import ProcessSimpleSerializer + +class SubplanGanttSerializer(serializers.ModelSerializer): + count = serializers.IntegerField(source='main_count') + count_real = serializers.IntegerField(source='main_count_real') + count_ok = serializers.IntegerField(source='main_count_ok') + process_ = ProcessSimpleSerializer(source='process', read_only=True) + class Meta: + model = SubProductionPlan + fields = ['id', 'number', 'start_date', 'end_date', 'count', 'count_real', 'count_ok', 'start_date_real', 'end_date_real', 'process_'] + +class PlanGanttSerializer(serializers.ModelSerializer): + children = serializers.SerializerMethodField() + class Meta: + model = ProductionPlan + fields = ['id', 'number', 'start_date', 'end_date', 'children', 'count', 'count_real', 'count_ok'] + + def get_children(self, obj): + subplans = SubProductionPlan.objects.filter(production_plan=obj).order_by('process__number') + return SubplanGanttSerializer(instance=subplans, many=True).data \ No newline at end of file diff --git a/hb_server/apps/srm/urls.py b/hb_server/apps/srm/urls.py new file mode 100644 index 0000000..cbaf2ed --- /dev/null +++ b/hb_server/apps/srm/urls.py @@ -0,0 +1,13 @@ +from django.db.models import base +from rest_framework import urlpatterns +from django.urls import path, include +from rest_framework.routers import DefaultRouter + +from apps.srm.views import GanttPlan + +router = DefaultRouter() +urlpatterns = [ + path('gantt/plan/', GanttPlan.as_view()), + path('', include(router.urls)), +] + diff --git a/hb_server/apps/srm/views.py b/hb_server/apps/srm/views.py index 59607d6..a739725 100644 --- a/hb_server/apps/srm/views.py +++ b/hb_server/apps/srm/views.py @@ -1,8 +1,17 @@ from django.shortcuts import render +from rest_framework import serializers from rest_framework.generics import ListAPIView +from rest_framework.response import Response +from apps.pm.models import ProductionPlan, SubProductionPlan +from apps.srm.serializers import PlanGanttSerializer # Create your views here. -class GanttOrder(ListAPIView): +class GanttPlan(ListAPIView): """ - 订单-计划-子计划甘特图 - """ \ No newline at end of file + 计划-子计划甘特图 + """ + perms_map = {'get':'*'} + serializer_class = PlanGanttSerializer + queryset = ProductionPlan.objects.filter(is_deleted=False, is_planed=True).prefetch_related('subplan_plan', 'subplan_plan__process') + ordering = ['-id'] + diff --git a/hb_server/server/urls.py b/hb_server/server/urls.py index 3db8e36..b1893f2 100644 --- a/hb_server/server/urls.py +++ b/hb_server/server/urls.py @@ -69,7 +69,7 @@ urlpatterns = [ path('api/qm/', include('apps.qm.urls')), path('api/pm/', include('apps.pm.urls')), path('api/wpm/', include('apps.wpm.urls')), - + path('api/srm/', include('apps.srm.urls')), # 工具 path('api/utils/signature/', GenSignature.as_view()), path('api/utils/develop/', UpdateDevelop.as_view()), From 70f6ade5e0901822942c8bc778c19a311f9784a9 Mon Sep 17 00:00:00 2001 From: shilixia <2309368887@qq.com> Date: Mon, 13 Dec 2021 14:29:06 +0800 Subject: [PATCH 02/20] xiugai --- hb_client/src/router/index.js | 12 +- hb_client/src/views/inm/product.vue | 55 +-------- hb_client/src/views/inm/wproduct.vue | 1 + hb_client/src/views/qm/product.vue | 165 +++++++++++++++++++++++++++ hb_client/src/views/sam/sales.vue | 111 +++++++++++------- 5 files changed, 245 insertions(+), 99 deletions(-) create mode 100644 hb_client/src/views/qm/product.vue diff --git a/hb_client/src/router/index.js b/hb_client/src/router/index.js index bb1f9c7..f5698c8 100644 --- a/hb_client/src/router/index.js +++ b/hb_client/src/router/index.js @@ -212,7 +212,7 @@ export const asyncRoutes = [ path: 'need', name: 'need', component: () => import('@/views/wpm/need'), - meta: { title: '半成品检验', icon: 'example', perms: ['index_manage'] } + meta: { title: '过程检验', icon: 'example', perms: ['index_manage'] } } , { @@ -305,15 +305,15 @@ export const asyncRoutes = [ { path: '/qm', component: Layout, - redirect: '/qm/standard', + redirect: '/qm/product', name: 'qm', meta: { title: '质量管理', icon: 'example', perms: ['equipment_set'] }, children: [ { - path: 'standard', - name: 'standard', - component: () => import('@/views/qm/standard'), - meta: { title: '标准', icon: 'example', perms: ['index_manage'] } + path: 'product', + name: 'product', + component: () => import('@/views/qm/product'), + meta: { title: '军检', icon: 'example', perms: ['index_manage'] } }, { path: 'testitem', diff --git a/hb_client/src/views/inm/product.vue b/hb_client/src/views/inm/product.vue index dc4d61f..e5dddef 100644 --- a/hb_client/src/views/inm/product.vue +++ b/hb_client/src/views/inm/product.vue @@ -45,21 +45,7 @@ 合格 - - - + - - - - - 合格 - 不合格 - - - - - - -
- 取消 - 确认 -
-
@@ -136,6 +95,7 @@ export default { //半成品列表 getList() { this.listLoading = true; + this.listQuery.material__type=1; getiproductList(this.listQuery).then((response) => { if (response.data) { this.iproductData= response.data; @@ -147,18 +107,7 @@ export default { this.saleproduct=scope.row.id; this.dialogVisible=true; }, - smtconfirm(){ - saleMtest(this.saleproduct,this.mtest).then((res) => { - - if (res.code >= 200) { - this.getList(); - this.dialogVisible = false; - this.$message.success("成功"); - } - - }); - } }, }; diff --git a/hb_client/src/views/inm/wproduct.vue b/hb_client/src/views/inm/wproduct.vue index d4ff5cf..bb46bf3 100644 --- a/hb_client/src/views/inm/wproduct.vue +++ b/hb_client/src/views/inm/wproduct.vue @@ -76,6 +76,7 @@ export default { //半成品列表 getList() { this.listLoading = true; + this.listQuery.material__type=2; getiproductList(this.listQuery).then((response) => { if (response.data) { this.iproductData= response.data; diff --git a/hb_client/src/views/qm/product.vue b/hb_client/src/views/qm/product.vue new file mode 100644 index 0000000..ac58135 --- /dev/null +++ b/hb_client/src/views/qm/product.vue @@ -0,0 +1,165 @@ + + diff --git a/hb_client/src/views/sam/sales.vue b/hb_client/src/views/sam/sales.vue index 75a1ebc..a6f53ce 100644 --- a/hb_client/src/views/sam/sales.vue +++ b/hb_client/src/views/sam/sales.vue @@ -143,10 +143,48 @@ -
- -
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
@@ -183,10 +221,11 @@ export default { page: 1, page_size: 20, }, + iproducts:[], orderoptions:[], customeroptions:[], materialoptions:[], - iproductoptions:[], + iproductoptions:"", dialogVisible: false, dialogType: "new", @@ -221,19 +260,12 @@ export default { if (response.data) { this.sale.customer = response.data.customer; this.sale.product = response.data.product; - this.iproductoptions=[]; - getiproductList({material: this.sale.product,page:0}).then((response) => { + getiproductList({page:0,material__type:1,material:this.sale.product}).then((response) => { if (response.data) { - response.data.forEach((item) => { - this.iproductoptions.push({ - label: item.number+"__"+item.material_.name+"__"+(item.is_mtested==true?"已军检":"未军检") , - key: item.id - }) - }); + this.iproductoptions=response.data; } - + }); - } @@ -270,39 +302,27 @@ export default { }); }, - selectproduct(selval) - { - this.iproductoptions=[]; - getiproductList({material:selval,page:0}).then((response) => { - if (response.data) { - response.data.forEach((item) => { - this.iproductoptions.push({ - label: item.number+"__"+item.material_.name+"__"+(item.is_mtested==true?"已军检":"未军检") , - key: item.id - }) - }); - } - - }); - - }, + //成品 getproductList() { - this.iproductoptions=[], - getiproductList({page:0}).then((response) => { + + getiproductList({page:0,material__type:1}).then((response) => { if (response.data) { - response.data.forEach((item) => { - this.iproductoptions.push({ - label: item.number+"__"+item.material_.name+"__"+(item.is_mtested==true?"已军检":"未军检") , - key: item.id - }) - }); + this.iproductoptions=response.data; } }); }, - +//根据选择的产品弹出对应库里的产品 +selectproduct(){ + getiproductList({page:0,material__type:1,material:this.sale.product}).then((response) => { + if (response.data) { + this.iproductoptions=response.data; + } + + }); +}, handleFilter() { @@ -320,7 +340,7 @@ export default { this.sale = Object.assign({}, defaulteSale); this.dialogType = "new"; this.dialogVisible = true; - this.iproductoptions=[]; + this.iproducts=[]; this.$nextTick(() => { this.$refs["Form"].clearValidate(); }); @@ -364,6 +384,17 @@ export default { } }); } else { + + this.$refs.multipleTable.selection.forEach((item) => { + this.iproducts.push( + item.id + ); + + }); + + + + this.sale.iproducts=this.iproducts; createSale(this.sale).then((res) => { if (res.code >= 200) { this.getList(); From cff7457b50b225fb96927c3dd5ff824e82c13bc8 Mon Sep 17 00:00:00 2001 From: shilixia <2309368887@qq.com> Date: Mon, 13 Dec 2021 14:48:37 +0800 Subject: [PATCH 03/20] xiugai --- hb_client/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hb_client/package.json b/hb_client/package.json index 0a17f55..f39a479 100644 --- a/hb_client/package.json +++ b/hb_client/package.json @@ -22,6 +22,7 @@ "compression-webpack-plugin": "^5.0.1", "d3": "^5.14.2", "dagre-d3": "^0.6.4", + "dhtmlx-gantt": "^6.2.1", "element-ui": "^2.15.5", "file-saver": "^2.0.2", "fuse.js": "^6.4.6", @@ -30,6 +31,7 @@ "nprogress": "0.2.0", "path-to-regexp": "^6.2.0", "vue": "^2.6.14", + "vue-function-api": "^2.1.2", "vue-json-editor": "^1.4.3", "vue-quill-editor": "^3.0.6", "vue-router": "^3.5.2", From 1285fdb9a1f484e9d0c6d3b62d006209ace74ea3 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 14 Dec 2021 13:12:05 +0800 Subject: [PATCH 04/20] =?UTF-8?q?=E6=A3=80=E9=AA=8C=E8=AE=B0=E5=BD=95?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B8=8E=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pm/migrations/0017_auto_20211213_1401.py | 49 ++++++++++++++ hb_server/apps/pm/models.py | 12 ++-- .../0017_alter_testrecord_wproduct.py | 20 ++++++ .../migrations/0018_testrecord_is_submited.py | 18 ++++++ hb_server/apps/qm/models.py | 5 +- hb_server/apps/qm/serializers.py | 64 ++++++++++++++----- hb_server/apps/qm/views.py | 26 +++++++- .../apps/wf/migrations/0018_workflow_key.py | 18 ++++++ hb_server/apps/wf/models.py | 2 +- .../wpm/migrations/0032_auto_20211214_1245.py | 36 +++++++++++ hb_server/apps/wpm/models.py | 49 ++++++++++++-- hb_server/apps/wpm/serializers.py | 3 +- hb_server/apps/wpm/services.py | 37 ++++++++++- hb_server/apps/wpm/views.py | 41 ++++-------- 14 files changed, 317 insertions(+), 63 deletions(-) create mode 100644 hb_server/apps/pm/migrations/0017_auto_20211213_1401.py create mode 100644 hb_server/apps/qm/migrations/0017_alter_testrecord_wproduct.py create mode 100644 hb_server/apps/qm/migrations/0018_testrecord_is_submited.py create mode 100644 hb_server/apps/wf/migrations/0018_workflow_key.py create mode 100644 hb_server/apps/wpm/migrations/0032_auto_20211214_1245.py diff --git a/hb_server/apps/pm/migrations/0017_auto_20211213_1401.py b/hb_server/apps/pm/migrations/0017_auto_20211213_1401.py new file mode 100644 index 0000000..9fa357e --- /dev/null +++ b/hb_server/apps/pm/migrations/0017_auto_20211213_1401.py @@ -0,0 +1,49 @@ +# Generated by Django 3.2.9 on 2021-12-13 06:01 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0016_auto_20211209_1638'), + ] + + operations = [ + migrations.AlterField( + model_name='productionplan', + name='count', + field=models.PositiveIntegerField(default=1, verbose_name='生产数量'), + ), + migrations.AlterField( + model_name='productionplan', + name='count_ok', + field=models.PositiveIntegerField(default=0, verbose_name='合格数'), + ), + migrations.AlterField( + model_name='productionplan', + name='count_real', + field=models.PositiveIntegerField(default=0, verbose_name='实际产出数'), + ), + migrations.AlterField( + model_name='subproductionplan', + name='main_count', + field=models.PositiveIntegerField(default=0, verbose_name='应产出数'), + ), + migrations.AlterField( + model_name='subproductionplan', + name='main_count_ok', + field=models.PositiveIntegerField(default=0, verbose_name='合格数'), + ), + migrations.AlterField( + model_name='subproductionplan', + name='main_count_real', + field=models.PositiveIntegerField(default=0, verbose_name='实际产出数'), + ), + migrations.AlterField( + model_name='subproductionplan', + name='production_plan', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subplan_plan', to='pm.productionplan', verbose_name='关联主生产计划'), + ), + ] diff --git a/hb_server/apps/pm/models.py b/hb_server/apps/pm/models.py index 346428f..7588491 100644 --- a/hb_server/apps/pm/models.py +++ b/hb_server/apps/pm/models.py @@ -24,9 +24,9 @@ class ProductionPlan(CommonAModel): number = models.CharField('编号', max_length=50, unique=True) order = models.ForeignKey(Order, verbose_name='关联订单', null=True, blank=True, on_delete=models.SET_NULL) product = models.ForeignKey(Material, verbose_name='生产产品', on_delete=models.CASCADE) - count = models.IntegerField('生产数量', default=1) - count_real = models.IntegerField('实际产出数', default=0) - count_ok = models.IntegerField('合格数', default=0) + count = models.PositiveIntegerField('生产数量', default=1) + count_real = models.PositiveIntegerField('实际产出数', default=0) + count_ok = models.PositiveIntegerField('合格数', default=0) start_date = models.DateField('计划开工日期') end_date = models.DateField('计划完工日期') is_planed = models.BooleanField('是否已排产', default=False) @@ -63,9 +63,9 @@ class SubProductionPlan(CommonAModel): process = models.ForeignKey(Process, verbose_name='关联大工序', on_delete=models.CASCADE) 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) + main_count = models.PositiveIntegerField('应产出数', default=0) + main_count_real = models.PositiveIntegerField('实际产出数', default=0) + main_count_ok = models.PositiveIntegerField('合格数', default=0) steps = models.JSONField('工艺步骤', default=list) diff --git a/hb_server/apps/qm/migrations/0017_alter_testrecord_wproduct.py b/hb_server/apps/qm/migrations/0017_alter_testrecord_wproduct.py new file mode 100644 index 0000000..1c70b53 --- /dev/null +++ b/hb_server/apps/qm/migrations/0017_alter_testrecord_wproduct.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.9 on 2021-12-13 06:01 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0031_auto_20211209_1638'), + ('qm', '0016_auto_20211210_1338'), + ] + + operations = [ + migrations.AlterField( + model_name='testrecord', + name='wproduct', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='test_wproduct', to='wpm.wproduct', verbose_name='关联的动态产品'), + ), + ] diff --git a/hb_server/apps/qm/migrations/0018_testrecord_is_submited.py b/hb_server/apps/qm/migrations/0018_testrecord_is_submited.py new file mode 100644 index 0000000..89c230b --- /dev/null +++ b/hb_server/apps/qm/migrations/0018_testrecord_is_submited.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-12-14 04:45 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0017_alter_testrecord_wproduct'), + ] + + operations = [ + migrations.AddField( + model_name='testrecord', + name='is_submited', + field=models.BooleanField(default=False, verbose_name='是否提交'), + ), + ] diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index 735c34e..560b4a4 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -1,7 +1,7 @@ from django.db import models from django.db.models.enums import Choices from apps.mtm.models import RecordForm, RecordFormField -from apps.system.models import CommonAModel, File +from apps.system.models import CommonADModel, CommonAModel, File from utils.model import BaseModel # Create your models here. class Standard(CommonAModel): @@ -43,7 +43,7 @@ class AnalysisItem(CommonAModel): class Meta: verbose_name = '检验分析项' -class TestRecord(CommonAModel): +class TestRecord(CommonADModel): """ 检验记录 """ @@ -70,6 +70,7 @@ class TestRecord(CommonAModel): 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) origin_test = models.ForeignKey('self', verbose_name='原检验记录', on_delete=models.CASCADE, null=True, blank=True) + is_submited = models.BooleanField('是否提交', default=False) remark = models.TextField('备注', default='') diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index 2ff328b..8dc187b 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -3,6 +3,7 @@ from apps.mtm.models import RecordForm, RecordFormField from apps.mtm.serializers import RecordFormFieldSerializer, RecordFormSimpleSerializer from apps.system.serializers import FileSimpleSerializer from .models import Standard, TestItem, TestRecord, TestRecordItem +from django.db import transaction class StandardCreateUpdateSerializer(serializers.ModelSerializer): class Meta: @@ -38,7 +39,13 @@ class AnalysisItemSerializer(serializers.ModelSerializer): class TestRecordItemCreateSerializer(serializers.ModelSerializer): class Meta: model = TestRecordItem - fields = ['form_field', 'field_value'] + fields = ['form_field', 'field_value', 'is_testok'] + +class TestRecordItemUpdateSerializer(serializers.ModelSerializer): + class Meta: + model = TestRecordItem + fields = ['id', 'field_value', 'is_testok'] + class TestRecordItemSerializer(serializers.ModelSerializer): class Meta: @@ -56,24 +63,49 @@ class TestRecordListSerializer(serializers.ModelSerializer): model = TestRecord fields = '__all__' - -class TestRecordDetailSerializer(serializers.ModelSerializer): +class TestRecordDetailBaseSerializer(serializers.ModelSerializer): form_ = RecordFormSimpleSerializer(source='form', read_only=True) - record_data_ = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True) + record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True) + class Meta: + model = TestRecord + fields = '__all__' + +class TestRecordDetailSerializer(serializers.ModelSerializer): + form_ = RecordFormSimpleSerializer(source='form', read_only=True) + record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True) + # record_data_ = serializers.SerializerMethodField() + origin_test_ = TestRecordDetailBaseSerializer(source='origin_test', read_only=True) class Meta: model = TestRecord fields = '__all__' - - @staticmethod - def setup_eager_loading(queryset): - queryset = queryset.select_related('form','fifo_item') - return queryset # def get_record_data_(self, obj): - # record_data = obj.record_data - # all_fields = RecordFormField.objects.filter(form=obj.form, is_deletd=False).order_by('sort') - # all_fields_l = RecordFormFieldSerializer(instance=all_fields, many=True).data - # for i in all_fields_l: - # key = i['field_key'] - # i['field_value'] = record_data.get(key, None) - # return all_fields_l \ No newline at end of file + # items_data = TestRecordItemSerializer(instance=obj.item_test_record, many=True).data + # if obj.origin_test and obj.type == TestRecord.TEST_PROCESS_RE: + # origin_ + + def to_representation(self, instance): + ret = super().to_representation(instance) + if instance.origin_test and instance.type == TestRecord.TEST_PROCESS_RE: + origin_test = ret['origin_test'] + o_dict = {} + for i in origin_test['record_data']: + o_dict[i['field_key']] = i['field_value'] + for i in ret['record_data']: + i['origin_value'] = o_dict[i['field_key']] if i['field_key'] in o_dict else None + return super().to_representation(instance) + +class TestRecordUpdateSerializer(serializers.ModelSerializer): + record_data = TestRecordItemUpdateSerializer(source='item_test_record', many=True) + class Meta: + model = TestRecord + fields = ['is_testok', 'record_data'] + + def update(self, instance, validated_data): + with transaction.atomic(): + record_data = validated_data.pop(validated_data) + for attr, value in validated_data.items(): + setattr(instance, attr, value) + instance.save() + self.record_data.save() + return instance diff --git a/hb_server/apps/qm/views.py b/hb_server/apps/qm/views.py index 8b3b80e..0e602e0 100644 --- a/hb_server/apps/qm/views.py +++ b/hb_server/apps/qm/views.py @@ -1,5 +1,6 @@ -from rest_framework.mixins import ListModelMixin, RetrieveModelMixin -from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer, TestRecordCreateSerializer, TestRecordDetailSerializer, TestRecordListSerializer +from rest_framework import exceptions, serializers +from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin +from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer, TestRecordCreateSerializer, TestRecordDetailSerializer, TestRecordListSerializer, TestRecordUpdateSerializer from apps.qm.models import Standard, TestItem, TestRecord, TestRecordItem from django.shortcuts import render from rest_framework.viewsets import GenericViewSet, ModelViewSet @@ -8,6 +9,10 @@ from rest_framework.exceptions import APIException from rest_framework.response import Response from rest_framework import status from django.db import transaction +from rest_framework.decorators import action + +from apps.wpm.models import WProduct +from apps.wpm.services import WpmServies # Create your views here. class StandardViewSet(CreateUpdateModelAMixin, ModelViewSet): """ @@ -43,7 +48,7 @@ class TestItemViewSet(CreateUpdateModelAMixin, ModelViewSet): return TestItemCreateUpdateSerializer return TestItemSerializer -class TestRecordViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): +class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet): """ 检测记录 """ @@ -58,8 +63,23 @@ class TestRecordViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): return TestRecordListSerializer elif self.action == 'retrieve': return TestRecordDetailSerializer + elif self.action == 'update': + return TestRecordUpdateSerializer return super().get_serializer_class() + def destroy(self, request, *args, **kwargs): + obj = self.get_object() + if obj.is_submited: + raise exceptions.APIException('该记录已提交不可删除') + return super().destroy(request, *args, **kwargs) + + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) + def submit(self, request, pk=None): + obj = self.get_object() + with transaction.atomic(): + WpmServies.update_wproduct_by_test(obj, request.user) + return Response() + # def create(self, request, *args, **kwargs): # serializer = self.get_serializer(data=request.data) # serializer.is_valid(raise_exception=True) diff --git a/hb_server/apps/wf/migrations/0018_workflow_key.py b/hb_server/apps/wf/migrations/0018_workflow_key.py new file mode 100644 index 0000000..821adc1 --- /dev/null +++ b/hb_server/apps/wf/migrations/0018_workflow_key.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-12-13 06:01 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wf', '0017_auto_20211203_1501'), + ] + + operations = [ + migrations.AddField( + model_name='workflow', + name='key', + field=models.CharField(blank=True, max_length=20, null=True, unique=True, verbose_name='工作流标识'), + ), + ] diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index ba8c745..127b18d 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -13,7 +13,7 @@ class Workflow(CommonAModel): 工作流 """ name = models.CharField('名称', max_length=50) - key = models.CharField('工作流标识', unique=True, max_length=20) + key = models.CharField('工作流标识', unique=True, max_length=20, null=True, blank=True) sn_prefix = models.CharField('流水号前缀', max_length=50, default='hb') description = models.CharField('描述', max_length=200) view_permission_check = models.BooleanField('查看权限校验', default=True, help_text='开启后,只允许工单的关联人(创建人、曾经的处理人)有权限查看工单') diff --git a/hb_server/apps/wpm/migrations/0032_auto_20211214_1245.py b/hb_server/apps/wpm/migrations/0032_auto_20211214_1245.py new file mode 100644 index 0000000..2107312 --- /dev/null +++ b/hb_server/apps/wpm/migrations/0032_auto_20211214_1245.py @@ -0,0 +1,36 @@ +# Generated by Django 3.2.9 on 2021-12-14 04:45 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wf', '0018_workflow_key'), + ('qm', '0018_testrecord_is_submited'), + ('wpm', '0031_auto_20211209_1638'), + ] + + operations = [ + migrations.AddField( + model_name='wproduct', + name='test', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wp_test', to='qm.testrecord', verbose_name='当前检验'), + ), + migrations.AddField( + model_name='wproduct', + name='ticket', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wp_ticket', to='wf.ticket', verbose_name='当前工单'), + ), + migrations.AlterField( + model_name='wproduct', + name='operation', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wp_operation', to='wpm.operation', verbose_name='当前操作'), + ), + migrations.AlterField( + model_name='wprouctticket', + name='ticket', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wt_ticket', to='wf.ticket', verbose_name='关联工单'), + ), + ] diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 182ffe8..5cdd3c7 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -1,4 +1,5 @@ import re +from rest_framework import exceptions from django.db import models from django.db.models.base import Model import django.utils.timezone as timezone @@ -7,6 +8,7 @@ from apps.inm.models import FIFO, WareHouse from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress from apps.qm.models import TestRecord from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File +from apps.wf.models import Ticket from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial @@ -54,15 +56,54 @@ class WProduct(CommonAModel): 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) - operation = models.ForeignKey('wpm.operation', verbose_name='关联操作', + operation = models.ForeignKey('wpm.operation', verbose_name='当前操作', on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation') + test = models.ForeignKey('qm.testrecord', verbose_name='当前检验', + on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_test') + ticket = models.ForeignKey('wf.ticket', verbose_name='当前工单', + on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_ticket') @property def last_process_test(self): """ - 最后的工序自检 + 最后提交的工序自检 """ - return self.test_wproduct.filter(type=TestRecord.TEST_PROCESS).order_by('-id').first() + return self.test_wproduct.filter(type=TestRecord.TEST_PROCESS, is_submited=True).order_by('-id').first() + + # @property + # def last_test(self): + # """ + # 最后提交的检验 + # """ + # return self.test_wproduct.filter(is_submited=True).order_by('-id').first() + + # @property + # def current_test(self): + # """ + # 当前未提交的检验 + # """ + # trs = self.test_wproduct.filter(is_submited=False).order_by('-id') + # if trs.count() == 1: + # return trs[0] + # elif trs.count() == 0: + # return None + # else: + # raise exceptions.APIException('存在多条未提交检验记录') + + # @property + # def current_ticket(self): + # """ + # 当前是否有进行中工单 + # """ + # tickets = Ticket.objects.filter(wt_ticket__wproduct=self, act_state=Ticket.TICKET_ACT_STATE_ONGOING).order_by('-id') + # if tickets.count() == 1: + # return tickets[0] + # elif tickets.count() == 0: + # return None + # else: + # raise exceptions.APIException('存在多条进行中工单') + + class WprouctTicket(CommonAModel): """ 玻璃审批工单 @@ -72,7 +113,7 @@ class WprouctTicket(CommonAModel): material = models.ForeignKey(Material, verbose_name='所在物料状态', on_delete=models.CASCADE) step = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='所在子生产计划', on_delete=models.CASCADE) - ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE) + ticket = models.ForeignKey('wf.ticket', verbose_name='关联工单', on_delete=models.CASCADE, related_name='wt_ticket') class Pick(CommonADModel): """ diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index ca3da1d..7553d57 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -290,7 +290,7 @@ class WpmTestRecordCreateSerializer(serializers.ModelSerializer): is_testok = serializers.BooleanField(required=False) class Meta: model = TestRecord - fields = ['form', 'record_data', 'is_testok', 'wproduct'] + fields = ['form', 'record_data', 'is_testok', 'wproduct', 'is_submited'] class WpmTestFormInitSerializer(serializers.Serializer): wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True) @@ -304,6 +304,7 @@ class WpmTestFormInitSerializer(serializers.Serializer): raise exceptions.APIException('请指定检查表') return super().validate(attrs) + class WplanPutInSerializer(serializers.Serializer): warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") remark = serializers.CharField(label="入库备注", required =False) diff --git a/hb_server/apps/wpm/services.py b/hb_server/apps/wpm/services.py index 20f2870..7ca4774 100644 --- a/hb_server/apps/wpm/services.py +++ b/hb_server/apps/wpm/services.py @@ -1,7 +1,10 @@ from typing import List -from apps.pm.models import SubProductionPlan -from apps.mtm.models import Step, SubprodctionMaterial +from apps.pm.models import SubProductionPlan, SubProductionProgress +from apps.mtm.models import Material, Step, SubprodctionMaterial +from apps.qm.models import TestRecord +from apps.system.models import User from apps.wpm.models import WProduct +from utils.tools import ranstr class WpmServies(object): @classmethod @@ -31,4 +34,32 @@ class WpmServies(object): """ 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 + return splans + + @classmethod + def update_wproduct_by_test(cls, test:TestRecord, user:User): + """ + 根据检测结果更新玻璃及相关状态 + """ + is_testok = test.is_testok + wproduct = test.wproduct + if is_testok: + if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检 + wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT + elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD: # 成品检验 + wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST + else: + wproduct.act_state = WProduct.WPR_ACT_STATE_OK + if wproduct.number is None: # 产生半成品编号 + wproduct.number = 'WP'+ranstr(7) + # 更新子计划状态 + # 更新子计划主产品数 + instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, + is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) + instance.count_ok = instance.count_ok + 1 # 这个地方可能会有问题 + instance.save() + else:# 如果不合格 + wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK + # 需要走不合格品审理的工单 + wproduct.update_by = user + wproduct.save() \ No newline at end of file diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 4317deb..ad6e4bb 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -194,9 +194,10 @@ class WProductViewSet(ListModelMixin, GenericViewSet): vdata = serializer.validated_data wproduct = vdata['wproduct'] form = vdata.get('form', None) - + if wproduct.test: + raise exceptions.APIException('存在进行中检验') - # 如果是复检记录, 需要带入原数据 + # 如果是复检, 需要带入原数据 if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 查找最近一条检验记录 trs = wproduct.last_process_test @@ -205,7 +206,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): data = RecordFormDetailSerializer(instance=trs.form).data data['origin_test'] = origin_test o_dict = {} - for i in origin_test['record_data_']: + for i in origin_test['record_data']: o_dict[i['field_key']] = i['field_value'] for i in data['form_fields']: i['origin_value'] = o_dict[i['field_key']] if i['field_key'] in o_dict else None @@ -221,7 +222,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): @transaction.atomic def test(self, request, pk=None): """ - 检测 + 检测记录提交 """ serializer = WpmTestRecordCreateSerializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -237,6 +238,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): savedict = dict(create_by = self.request.user, material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan, step=wproduct.step) if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: + savedict['origin_test'] = wproduct.last_process_test savedict['type'] = TestRecord.TEST_PROCESS_RE elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST: savedict['type'] = TestRecord.TEST_FINAL @@ -257,29 +259,13 @@ class WProductViewSet(ListModelMixin, GenericViewSet): TestRecordItem.objects.bulk_create(tris) # 如果检测合格, 变更动态产品进行状态 - - if obj.is_testok: - if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检 - obj.origin_test = wproduct.last_process_test - obj.save() - wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT - elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOTEST and wproduct.material.type == Material.MA_TYPE_GOOD: # 成品检验 - wproduct.act_state = WProduct.WPR_ACT_STATE_TOFINALTEST - else: - wproduct.act_state = WProduct.WPR_ACT_STATE_OK - if wproduct.number is None: # 产生半成品编号 - wproduct.number = 'WP'+ranstr(7) - # 更新子计划状态 - # 更新子计划主产品数 - instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, - is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) - instance.count_ok = instance.count_ok + 1 # 这个地方可能会有问题 - instance.save() - else:# 如果不合格 - wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK - # 需要走不合格品审理单 - wproduct.update_by = request.user - wproduct.save() + if obj.is_submited: + WpmServies.update_wproduct_by_test(obj, request.user) + else: + # 保存当前检验 + wproduct.test = obj + wproduct.update_by = request.user + wproduct.save() return Response() @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer) @@ -379,6 +365,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): wproduct.save() return Response() + class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet): """ 生产操作记录 From 24d2f864af7f38a9915251b64632d914684c666f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 14 Dec 2021 13:32:26 +0800 Subject: [PATCH 05/20] =?UTF-8?q?update=5Fwproduct=5Fby=5Ftest=20=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/services.py | 1 + hb_server/apps/wpm/views.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/wpm/services.py b/hb_server/apps/wpm/services.py index 7ca4774..c58a1c8 100644 --- a/hb_server/apps/wpm/services.py +++ b/hb_server/apps/wpm/services.py @@ -62,4 +62,5 @@ class WpmServies(object): wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK # 需要走不合格品审理的工单 wproduct.update_by = user + wproduct.test = None wproduct.save() \ No newline at end of file diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index ad6e4bb..11a6c8b 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -258,7 +258,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): tris.append(TestRecordItem(**m)) TestRecordItem.objects.bulk_create(tris) - # 如果检测合格, 变更动态产品进行状态 + # 如果提交检验 if obj.is_submited: WpmServies.update_wproduct_by_test(obj, request.user) else: From e64347c27c206442a63a3c1a420fcf2ae40c78a7 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 14 Dec 2021 15:04:01 +0800 Subject: [PATCH 06/20] =?UTF-8?q?=E4=BF=AE=E6=94=B9testrecorditem=20?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=8F=8A=E5=AF=B9=E5=BA=94=E7=9A=84=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E6=8E=A5=E5=8F=A3=E5=8E=BB=E9=99=A4sort,need?= =?UTF-8?q?=5Fjudge?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/models.py | 2 ++ hb_server/apps/qm/models.py | 3 +-- hb_server/apps/qm/serializers.py | 8 +++++++- hb_server/apps/qm/views.py | 4 ++++ hb_server/apps/wpm/serializers.py | 2 +- hb_server/apps/wpm/views.py | 3 +-- 6 files changed, 16 insertions(+), 6 deletions(-) diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index d4b20d2..7815711 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -143,6 +143,7 @@ class RecordFormField(CommonAModel): FIELD_SELECTS = 'selects' FIELD_TEXTAREA = 'textarea' FIELD_DRAW = 'draw' + FIELD_TABLE = 'table' FIELD_FROMSYSTEM = 'fromsystem' field_type_choices = ( ('string', '字符串'), @@ -157,6 +158,7 @@ class RecordFormField(CommonAModel): ('select', '单选下拉'), ('selects', '多选下拉'), ('textarea', '文本域'), + ('table', '表格'), ('draw', '绘图'), ) high_rule_choices = ( diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index 560b4a4..80a9cc1 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -83,8 +83,7 @@ class TestRecordItem(BaseModel): field_key = models.CharField('字段标识', max_length=50) field_type = models.CharField('字段类型', choices=RecordForm.type_choices, max_length=50) field_value = models.JSONField('录入值', default=dict, blank=True) - need_judge = models.BooleanField('是否需要判定', default=False) - sort = models.IntegerField('排序号', default=1) + is_hidden = models.BooleanField('是否隐藏', default=False) 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/qm/serializers.py b/hb_server/apps/qm/serializers.py index 8dc187b..352fa89 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -44,10 +44,16 @@ class TestRecordItemCreateSerializer(serializers.ModelSerializer): class TestRecordItemUpdateSerializer(serializers.ModelSerializer): class Meta: model = TestRecordItem - fields = ['id', 'field_value', 'is_testok'] + fields = ['id', 'field_value', 'is_testok', 'is_hidden'] class TestRecordItemSerializer(serializers.ModelSerializer): + need_judge = serializers.BooleanField(source='form_field__need_judge', read_only=True) + rule_expression = serializers.JSONField(source='form_field__rule_expression', read_only=True) + display_expression = serializers.JSONField(source='form_field__display_expression', read_only=True) + is_hidden = serializers.BooleanField(source='form_field__is_hidden', read_only=True) + help_text = serializers.CharField(source='form_field__help_text', read_only=True) + sort = serializers.IntegerField(source='form_field__sort', read_only=True) class Meta: model = TestRecordItem fields = '__all__' diff --git a/hb_server/apps/qm/views.py b/hb_server/apps/qm/views.py index 0e602e0..1d9fb36 100644 --- a/hb_server/apps/qm/views.py +++ b/hb_server/apps/qm/views.py @@ -76,6 +76,10 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) def submit(self, request, pk=None): obj = self.get_object() + # 校验是否有未填项目 + if obj.type != TestRecord.TEST_PROCESS_RE: + if TestRecordItem.objects.filter(field_value__isnull=True, is_hidden=False).exists(): + raise exceptions.APIException('存在未填写项目') with transaction.atomic(): WpmServies.update_wproduct_by_test(obj, request.user) return Response() diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 7553d57..6c05e9c 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -282,7 +282,7 @@ class OperationSubmitSerializer(serializers.Serializer): class WpmTestRecordItemCreateSerializer(serializers.ModelSerializer): class Meta: model = TestRecordItem - fields = ['form_field', 'field_value', 'is_testok'] + fields = ['form_field', 'field_value', 'is_testok', 'is_hidden'] class WpmTestRecordCreateSerializer(serializers.ModelSerializer): record_data = WpmTestRecordItemCreateSerializer(many=True) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 11a6c8b..352cd97 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -210,6 +210,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): o_dict[i['field_key']] = i['field_value'] for i in data['form_fields']: i['origin_value'] = o_dict[i['field_key']] if i['field_key'] in o_dict else None + i['is_hidden'] = o_dict[i['is_hidden']] if i['is_hidden'] in o_dict else False else: raise exceptions.APIException('原工序检验记录不存在') else: @@ -251,8 +252,6 @@ class WProductViewSet(ListModelMixin, GenericViewSet): m['field_name'] = form_field.field_name m['field_key'] = form_field.field_key m['field_type'] = form_field.field_type - m['sort'] = form_field.sort - m['need_judge'] = form_field.need_judge m['is_testok'] = m['is_testok'] if 'is_testok' in m else None m['test_record'] = obj tris.append(TestRecordItem(**m)) From 9bf59ee40fda752106ff6ae9d295b1a486db6e0f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 14 Dec 2021 15:04:56 +0800 Subject: [PATCH 07/20] =?UTF-8?q?=E5=90=8C=E6=AD=A5=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 --- .../0042_alter_recordformfield_field_type.py | 18 +++++++++++++ .../qm/migrations/0019_auto_20211214_1504.py | 26 +++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 hb_server/apps/mtm/migrations/0042_alter_recordformfield_field_type.py create mode 100644 hb_server/apps/qm/migrations/0019_auto_20211214_1504.py diff --git a/hb_server/apps/mtm/migrations/0042_alter_recordformfield_field_type.py b/hb_server/apps/mtm/migrations/0042_alter_recordformfield_field_type.py new file mode 100644 index 0000000..029a7f1 --- /dev/null +++ b/hb_server/apps/mtm/migrations/0042_alter_recordformfield_field_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-12-14 07:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0041_alter_material_type'), + ] + + operations = [ + migrations.AlterField( + model_name='recordformfield', + name='field_type', + field=models.CharField(choices=[('string', '字符串'), ('int', '整型'), ('float', '浮点'), ('boolean', '布尔'), ('date', '日期'), ('time', '时间'), ('datetime', '日期时间'), ('radio', '单选'), ('checkbox', '多选'), ('select', '单选下拉'), ('selects', '多选下拉'), ('textarea', '文本域'), ('table', '表格'), ('draw', '绘图')], max_length=50, verbose_name='类型'), + ), + ] diff --git a/hb_server/apps/qm/migrations/0019_auto_20211214_1504.py b/hb_server/apps/qm/migrations/0019_auto_20211214_1504.py new file mode 100644 index 0000000..5be96de --- /dev/null +++ b/hb_server/apps/qm/migrations/0019_auto_20211214_1504.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.9 on 2021-12-14 07:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0018_testrecord_is_submited'), + ] + + operations = [ + migrations.RemoveField( + model_name='testrecorditem', + name='need_judge', + ), + migrations.RemoveField( + model_name='testrecorditem', + name='sort', + ), + migrations.AddField( + model_name='testrecorditem', + name='is_hidden', + field=models.BooleanField(default=False, verbose_name='是否隐藏'), + ), + ] From a30481810940381864b96531c0fd9b4f758a67a6 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 14 Dec 2021 15:22:51 +0800 Subject: [PATCH 08/20] =?UTF-8?q?testrecord=20list=20=E5=A2=9E=E5=8A=A0for?= =?UTF-8?q?m?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/qm/serializers.py | 1 + hb_server/apps/qm/views.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index 352fa89..431fbcd 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -65,6 +65,7 @@ class TestRecordCreateSerializer(serializers.ModelSerializer): fields = ['form', 'record_data', 'is_testok', 'fifo_item'] class TestRecordListSerializer(serializers.ModelSerializer): + form_ = RecordFormSimpleSerializer(source='form', read_only=True) class Meta: model = TestRecord fields = '__all__' diff --git a/hb_server/apps/qm/views.py b/hb_server/apps/qm/views.py index 1d9fb36..cbdcc8d 100644 --- a/hb_server/apps/qm/views.py +++ b/hb_server/apps/qm/views.py @@ -53,7 +53,7 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De 检测记录 """ perms_map = {'*': '*'} - queryset = TestRecord.objects.select_related('fifo_item', 'form').all() + queryset = TestRecord.objects.select_related('fifo_item', 'form').prefetch_related('item_test_record').all() serializer_class = TestRecordListSerializer filterset_fields = ['wproduct', 'material', 'step', 'subproduction_plan', 'fifo_item', 'origin_test', 'type'] ordering = ['-id'] From 7598e96d1f0afaaad2b9e00205ebbe2c77963750 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 14 Dec 2021 15:38:27 +0800 Subject: [PATCH 09/20] =?UTF-8?q?testrecord=20serializer=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E4=BA=BA=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/qm/serializers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index 431fbcd..571aed8 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -1,7 +1,7 @@ from rest_framework import serializers from apps.mtm.models import RecordForm, RecordFormField from apps.mtm.serializers import RecordFormFieldSerializer, RecordFormSimpleSerializer -from apps.system.serializers import FileSimpleSerializer +from apps.system.serializers import FileSimpleSerializer, UserSimpleSerializer from .models import Standard, TestItem, TestRecord, TestRecordItem from django.db import transaction @@ -66,6 +66,7 @@ class TestRecordCreateSerializer(serializers.ModelSerializer): class TestRecordListSerializer(serializers.ModelSerializer): form_ = RecordFormSimpleSerializer(source='form', read_only=True) + create_by_ = UserSimpleSerializer(source='create_by', read_only=True) class Meta: model = TestRecord fields = '__all__' @@ -73,6 +74,7 @@ class TestRecordListSerializer(serializers.ModelSerializer): class TestRecordDetailBaseSerializer(serializers.ModelSerializer): form_ = RecordFormSimpleSerializer(source='form', read_only=True) record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True) + create_by_ = UserSimpleSerializer(source='create_by', read_only=True) class Meta: model = TestRecord fields = '__all__' From 345d49ef673194b8e1ea50d7b2a49f40dd9bc747 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 14 Dec 2021 16:12:50 +0800 Subject: [PATCH 10/20] =?UTF-8?q?testrecord=20item=20serializer=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/qm/serializers.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index 571aed8..7762119 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -48,12 +48,12 @@ class TestRecordItemUpdateSerializer(serializers.ModelSerializer): class TestRecordItemSerializer(serializers.ModelSerializer): - need_judge = serializers.BooleanField(source='form_field__need_judge', read_only=True) - rule_expression = serializers.JSONField(source='form_field__rule_expression', read_only=True) - display_expression = serializers.JSONField(source='form_field__display_expression', read_only=True) - is_hidden = serializers.BooleanField(source='form_field__is_hidden', read_only=True) - help_text = serializers.CharField(source='form_field__help_text', read_only=True) - sort = serializers.IntegerField(source='form_field__sort', read_only=True) + need_judge = serializers.BooleanField(source='form_field.need_judge', read_only=True) + rule_expression = serializers.JSONField(source='form_field.rule_expression', read_only=True) + display_expression = serializers.JSONField(source='form_field.display_expression', read_only=True) + is_hidden = serializers.BooleanField(source='form_field.is_hidden', read_only=True) + help_text = serializers.CharField(source='form_field.help_text', read_only=True) + sort = serializers.IntegerField(source='form_field.sort', read_only=True) class Meta: model = TestRecordItem fields = '__all__' @@ -73,25 +73,26 @@ class TestRecordListSerializer(serializers.ModelSerializer): class TestRecordDetailBaseSerializer(serializers.ModelSerializer): form_ = RecordFormSimpleSerializer(source='form', read_only=True) - record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True) + record_data = serializers.SerializerMethodField() create_by_ = UserSimpleSerializer(source='create_by', read_only=True) class Meta: model = TestRecord fields = '__all__' + + def get_record_data(self, obj): + return TestRecordItemSerializer(instance=obj.item_test_record.order_by('form_field__sort'), many=True).data class TestRecordDetailSerializer(serializers.ModelSerializer): form_ = RecordFormSimpleSerializer(source='form', read_only=True) - record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True) - # record_data_ = serializers.SerializerMethodField() + # record_data = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True) + record_data = serializers.SerializerMethodField() origin_test_ = TestRecordDetailBaseSerializer(source='origin_test', read_only=True) class Meta: model = TestRecord fields = '__all__' - # def get_record_data_(self, obj): - # items_data = TestRecordItemSerializer(instance=obj.item_test_record, many=True).data - # if obj.origin_test and obj.type == TestRecord.TEST_PROCESS_RE: - # origin_ + def get_record_data(self, obj): + return TestRecordItemSerializer(instance=obj.item_test_record.order_by('form_field__sort'), many=True).data def to_representation(self, instance): ret = super().to_representation(instance) From 3dc67158fcc70932178a88e055616be7e5a2b918 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 14 Dec 2021 16:19:48 +0800 Subject: [PATCH 11/20] =?UTF-8?q?testrecord=20update=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E5=8C=96=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/qm/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index 7762119..1593b64 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -113,7 +113,7 @@ class TestRecordUpdateSerializer(serializers.ModelSerializer): def update(self, instance, validated_data): with transaction.atomic(): - record_data = validated_data.pop(validated_data) + record_data = validated_data.pop('record_data') for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() From 0a487d42775c0f06afaa5942ad6b60cba39561fa Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 08:45:57 +0800 Subject: [PATCH 12/20] tesrecord update bug --- hb_server/apps/inm/models.py | 4 ++-- hb_server/apps/inm/views.py | 6 +++--- hb_server/apps/qm/models.py | 2 +- hb_server/apps/qm/serializers.py | 15 +++++++-------- hb_server/apps/qm/views.py | 14 ++++++++++---- hb_server/apps/wpm/serializers.py | 2 +- hb_server/apps/wpm/services.py | 2 +- hb_server/apps/wpm/views.py | 4 ++-- 8 files changed, 27 insertions(+), 22 deletions(-) diff --git a/hb_server/apps/inm/models.py b/hb_server/apps/inm/models.py index 10248cd..e1e9f1a 100644 --- a/hb_server/apps/inm/models.py +++ b/hb_server/apps/inm/models.py @@ -75,8 +75,8 @@ class FIFOItem(BaseModel): """ 出入库详细条目 """ - is_tested = models.BooleanField('是否已检测', default=False) - is_testok = models.BooleanField('是否检测合格', default=False) + is_tested = models.BooleanField('是否已检验', default=False) + is_testok = models.BooleanField('是否检验合格', default=False) warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='仓库') material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE) count = models.PositiveIntegerField('数量', default=0) diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index 5ef42dc..109feb6 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -87,14 +87,14 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=InmTestRecordCreateSerializer) def test(self, request, pk=None): """ - 检测 + 检验 """ serializer = InmTestRecordCreateSerializer(data=request.data) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data record_data = vdata.pop('record_data') if 'is_testok' not in vdata: - raise APIException('未填写检测结论') + raise APIException('未填写检验结论') with transaction.atomic(): obj = serializer.save(create_by = self.request.user) tris = [] @@ -111,7 +111,7 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): tris.append(TestRecordItem(**m)) TestRecordItem.objects.bulk_create(tris) - # 如果检测合格 + # 如果检验合格 if obj.fifo_item: obj.fifo_item.is_testok = True if obj.is_testok else False obj.fifo_item.is_tested = True diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index 80a9cc1..a0368f8 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -86,4 +86,4 @@ class TestRecordItem(BaseModel): is_hidden = models.BooleanField('是否隐藏', default=False) 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 + 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/qm/serializers.py b/hb_server/apps/qm/serializers.py index 1593b64..314fcd3 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -106,16 +106,15 @@ class TestRecordDetailSerializer(serializers.ModelSerializer): return super().to_representation(instance) class TestRecordUpdateSerializer(serializers.ModelSerializer): - record_data = TestRecordItemUpdateSerializer(source='item_test_record', many=True) + record_data = TestRecordItemUpdateSerializer(many=True) class Meta: model = TestRecord fields = ['is_testok', 'record_data'] def update(self, instance, validated_data): - with transaction.atomic(): - record_data = validated_data.pop('record_data') - for attr, value in validated_data.items(): - setattr(instance, attr, value) - instance.save() - self.record_data.save() - return instance + record_data = validated_data.pop('record_data') + for attr, value in validated_data.items(): + setattr(instance, attr, value) + instance.save() + self.record_data.save() + return instance diff --git a/hb_server/apps/qm/views.py b/hb_server/apps/qm/views.py index cbdcc8d..32d0334 100644 --- a/hb_server/apps/qm/views.py +++ b/hb_server/apps/qm/views.py @@ -50,7 +50,7 @@ class TestItemViewSet(CreateUpdateModelAMixin, ModelViewSet): class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin, GenericViewSet): """ - 检测记录 + 检验记录 """ perms_map = {'*': '*'} queryset = TestRecord.objects.select_related('fifo_item', 'form').prefetch_related('item_test_record').all() @@ -67,13 +67,19 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De return TestRecordUpdateSerializer return super().get_serializer_class() + def update(self, request, *args, **kwargs): + obj = self.get_object() + if obj.is_submited: + raise exceptions.APIException('该记录已提交不可编辑') + return super().update(request, *args, **kwargs) + def destroy(self, request, *args, **kwargs): obj = self.get_object() if obj.is_submited: raise exceptions.APIException('该记录已提交不可删除') return super().destroy(request, *args, **kwargs) - @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=TestRecordUpdateSerializer) def submit(self, request, pk=None): obj = self.get_object() # 校验是否有未填项目 @@ -90,7 +96,7 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De # vdata = serializer.validated_data # record_data = vdata.pop('record_data') # if 'is_testok' not in vdata: - # raise APIException('未填写检测结论') + # raise APIException('未填写检验结论') # with transaction.atomic(): # obj = serializer.save(create_by = self.request.user) # tris = [] @@ -107,7 +113,7 @@ class TestRecordViewSet(ListModelMixin, UpdateModelMixin, RetrieveModelMixin, De # tris.append(TestRecordItem(**m)) # TestRecordItem.objects.bulk_create(tris) - # # 如果检测合格 + # # 如果检验合格 # if obj.fifo_item: # obj.fifo_item.is_testok = True if obj.is_testok else False # obj.fifo_item.is_tested = True diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 6c05e9c..8ab6754 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -65,7 +65,7 @@ class PickSerializer(serializers.Serializer): if isLowLevel: iproducts = i.pop('iproducts') i['fifo'] = fifo - i['is_testok'] = True # 默认检测合格 + i['is_testok'] = True # 默认检验合格 i['subproduction_plan'] = sp fifoitem = FIFOItem.objects.create(**i) # 创建再下一个层级 diff --git a/hb_server/apps/wpm/services.py b/hb_server/apps/wpm/services.py index c58a1c8..9d56be0 100644 --- a/hb_server/apps/wpm/services.py +++ b/hb_server/apps/wpm/services.py @@ -39,7 +39,7 @@ class WpmServies(object): @classmethod def update_wproduct_by_test(cls, test:TestRecord, user:User): """ - 根据检测结果更新玻璃及相关状态 + 根据检验结果更新玻璃及相关状态 """ is_testok = test.is_testok wproduct = test.wproduct diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 352cd97..f7938ca 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -223,7 +223,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): @transaction.atomic def test(self, request, pk=None): """ - 检测记录提交 + 检验记录提交 """ serializer = WpmTestRecordCreateSerializer(data=request.data) serializer.is_valid(raise_exception=True) @@ -234,7 +234,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST, WProduct.WPR_ACT_STATE_TOCOMBTEST]: raise exceptions.APIException('该产品当前状态不可检验') if 'is_testok' not in vdata: - raise exceptions.APIException('未填写检测结论') + raise exceptions.APIException('未填写检验结论') savedict = dict(create_by = self.request.user, material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan, step=wproduct.step) From 80720a07349ae7b34c172cc514fb6e797cf213d5 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 09:33:35 +0800 Subject: [PATCH 13/20] testrecord update bug --- hb_server/apps/qm/serializers.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index 314fcd3..863196e 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -105,8 +105,14 @@ class TestRecordDetailSerializer(serializers.ModelSerializer): i['origin_value'] = o_dict[i['field_key']] if i['field_key'] in o_dict else None return super().to_representation(instance) +class TestRecordItemUpdatexSerializer(serializers.Serializer): + id = serializers.PrimaryKeyRelatedField(queryset=TestRecordItem.objects.all()) + field_value = serializers.JSONField(allow_null=True, required=False) + is_testok = serializers.BooleanField(allow_null=True, required=False) + is_hidden = serializers.BooleanField(default=False) + class TestRecordUpdateSerializer(serializers.ModelSerializer): - record_data = TestRecordItemUpdateSerializer(many=True) + record_data = TestRecordItemUpdatexSerializer(many=True) class Meta: model = TestRecord fields = ['is_testok', 'record_data'] @@ -116,5 +122,10 @@ class TestRecordUpdateSerializer(serializers.ModelSerializer): for attr, value in validated_data.items(): setattr(instance, attr, value) instance.save() - self.record_data.save() + for i in record_data: + tri = i['id'] + tri.field_value = i['field_value'] + tri.is_testok = i['is_testok'] + tri.is_hidden = i['is_hidden'] + tri.save() return instance From 275068a7a5b23fa0d5ac0e719bc5ce75906c5abe Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 09:51:16 +0800 Subject: [PATCH 14/20] testrecord update bug --- hb_server/apps/qm/serializers.py | 2 +- hb_server/apps/wpm/serializers.py | 16 ++++++++-------- hb_server/apps/wpm/views.py | 8 ++++++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index 863196e..f329d3a 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -112,7 +112,7 @@ class TestRecordItemUpdatexSerializer(serializers.Serializer): is_hidden = serializers.BooleanField(default=False) class TestRecordUpdateSerializer(serializers.ModelSerializer): - record_data = TestRecordItemUpdatexSerializer(many=True) + record_data = TestRecordItemUpdatexSerializer(many=True, write_only=True) class Meta: model = TestRecord fields = ['is_testok', 'record_data'] diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 8ab6754..e91038e 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -294,15 +294,15 @@ class WpmTestRecordCreateSerializer(serializers.ModelSerializer): class WpmTestFormInitSerializer(serializers.Serializer): wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True) - form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=False) + form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=True) - def validate(self, attrs): - wproduct = attrs['wproduct'] - form = attrs.get('form', None) - if wproduct.act_state != WProduct.WPR_ACT_STATE_TORETEST: - if not form: - raise exceptions.APIException('请指定检查表') - return super().validate(attrs) + # def validate(self, attrs): + # wproduct = attrs['wproduct'] + # form = attrs.get('form', None) + # if wproduct.act_state != WProduct.WPR_ACT_STATE_TORETEST: + # if not form: + # raise exceptions.APIException('请指定检查表') + # return super().validate(attrs) class WplanPutInSerializer(serializers.Serializer): diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index f7938ca..4d27966 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -193,7 +193,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): serializer.is_valid(raise_exception=True) vdata = serializer.validated_data wproduct = vdata['wproduct'] - form = vdata.get('form', None) + form = vdata['form'] if wproduct.test: raise exceptions.APIException('存在进行中检验') @@ -203,7 +203,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): trs = wproduct.last_process_test if trs: origin_test = TestRecordDetailSerializer(instance=trs).data - data = RecordFormDetailSerializer(instance=trs.form).data + data = RecordFormDetailSerializer(instance=form).data data['origin_test'] = origin_test o_dict = {} for i in origin_test['record_data']: @@ -365,6 +365,10 @@ class WProductViewSet(ListModelMixin, GenericViewSet): return Response() + def workflows(self, request, pk=None): + """ + 可发起的工作流 + """ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet): """ 生产操作记录 From 24738bfde01183d221eb0c1d319813ec9961aad2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 10:17:21 +0800 Subject: [PATCH 15/20] =?UTF-8?q?test=5Finit=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/serializers.py | 3 ++- hb_server/apps/wpm/views.py | 13 +++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index e91038e..3cab8b8 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -288,9 +288,10 @@ class WpmTestRecordCreateSerializer(serializers.ModelSerializer): record_data = WpmTestRecordItemCreateSerializer(many=True) wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True) is_testok = serializers.BooleanField(required=False) + origin_test = serializers.PrimaryKeyRelatedField(queryset=TestRecord.objects.all(), default=None) class Meta: model = TestRecord - fields = ['form', 'record_data', 'is_testok', 'wproduct', 'is_submited'] + fields = ['form', 'record_data', 'is_testok', 'wproduct', 'is_submited', 'origin_test'] class WpmTestFormInitSerializer(serializers.Serializer): wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 4d27966..b69ad27 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -196,15 +196,17 @@ class WProductViewSet(ListModelMixin, GenericViewSet): form = vdata['form'] if wproduct.test: raise exceptions.APIException('存在进行中检验') - + + data = RecordFormDetailSerializer(instance=form).data + data['origin_test'] = None # 如果是复检, 需要带入原数据 if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 查找最近一条检验记录 trs = wproduct.last_process_test if trs: origin_test = TestRecordDetailSerializer(instance=trs).data - data = RecordFormDetailSerializer(instance=form).data - data['origin_test'] = origin_test + data['origin_test_'] = origin_test + data['origin_test'] = origin_test.get('id', None) o_dict = {} for i in origin_test['record_data']: o_dict[i['field_key']] = i['field_value'] @@ -213,8 +215,6 @@ class WProductViewSet(ListModelMixin, GenericViewSet): i['is_hidden'] = o_dict[i['is_hidden']] if i['is_hidden'] in o_dict else False else: raise exceptions.APIException('原工序检验记录不存在') - else: - data = RecordFormDetailSerializer(instance=form).data # 后续加入系统自带数据 return Response(data) @@ -239,7 +239,8 @@ class WProductViewSet(ListModelMixin, GenericViewSet): savedict = dict(create_by = self.request.user, material=wproduct.material, number=wproduct.number, subproduction_plan=wproduct.subproduction_plan, step=wproduct.step) if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: - savedict['origin_test'] = wproduct.last_process_test + if not vdata['origin_test']: + raise exceptions.APIException('自检记录不存在') savedict['type'] = TestRecord.TEST_PROCESS_RE elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST: savedict['type'] = TestRecord.TEST_FINAL From 5e057e78b2ff52e9678788ef763ab9b43d53d883 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 10:21:05 +0800 Subject: [PATCH 16/20] =?UTF-8?q?wpm=20test=E6=8F=90=E4=BA=A4is=5Fhidden?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 1 + 1 file changed, 1 insertion(+) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index b69ad27..4fe80e2 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -254,6 +254,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): m['field_key'] = form_field.field_key m['field_type'] = form_field.field_type m['is_testok'] = m['is_testok'] if 'is_testok' in m else None + m['is_hidden'] = m['is_hidden'] if 'is_hidden' in m else None m['test_record'] = obj tris.append(TestRecordItem(**m)) TestRecordItem.objects.bulk_create(tris) From 4acffd6f9eb6cd3acef562483411f2c1c157d156 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 16:02:33 +0800 Subject: [PATCH 17/20] =?UTF-8?q?test-init=E5=A2=9E=E5=8A=A0form=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/qm/models.py | 2 +- hb_server/apps/wf/models.py | 12 ------------ hb_server/apps/wpm/views.py | 5 ++++- 3 files changed, 5 insertions(+), 14 deletions(-) diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index a0368f8..ed7e582 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -78,7 +78,7 @@ class TestRecordItem(BaseModel): """ 记录表格字段值 """ - form_field = models.ForeignKey(RecordFormField, verbose_name='关联字段', on_delete=models.CASCADE, db_constraint=False) + form_field = models.ForeignKey(RecordFormField, verbose_name='关联自定义表格字段', on_delete=models.CASCADE, db_constraint=False) field_name = models.CharField('字段名', max_length=50) field_key = models.CharField('字段标识', max_length=50) field_type = models.CharField('字段类型', choices=RecordForm.type_choices, max_length=50) diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index 127b18d..5d6625d 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -213,18 +213,6 @@ class Ticket(CommonBModel): multi_all_person = models.JSONField('全部处理的结果', default=dict, blank=True, help_text='需要当前状态处理人全部处理时实际的处理结果,json格式') -# class TicketCustomField(BaseModel): -# """ -# 工单数据,自定义字段值 -# """ -# ticket = models.ForeignKey(Ticket, verbose_name='关联工单', on_delete=models.CASCADE) -# form_field = models.ForeignKey(CustomField, verbose_name='关联字段', on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True) -# field_name = models.CharField('字段名', max_length=50) -# field_key = models.CharField('字段标识', max_length=50) -# field_type = models.CharField('字段类型', choices=CustomField.field_type_choices, max_length=50) -# field_value = models.JSONField('录入值', default=dict, blank=True) -# sort = models.IntegerField('排序号', default=1) - class TicketFlow(BaseModel): """ 工单流转日志 diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 4fe80e2..3a674e7 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -16,6 +16,7 @@ from apps.qm.serializers import TestRecordDetailSerializer from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action +from apps.wf.models import Workflow from apps.wpm.filters import WMaterialFilterSet from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem @@ -199,6 +200,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): data = RecordFormDetailSerializer(instance=form).data data['origin_test'] = None + data['form'] = form.id # 如果是复检, 需要带入原数据 if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 查找最近一条检验记录 @@ -366,11 +368,12 @@ class WProductViewSet(ListModelMixin, GenericViewSet): wproduct.save() return Response() - + @action(methods=['get'], detail=False, perms_map={'post':'*'}) def workflows(self, request, pk=None): """ 可发起的工作流 """ + wfs = Workflow.objects.get() class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet): """ 生产操作记录 From f6225856c4970945be33fd835d422c97950e934b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 16:27:52 +0800 Subject: [PATCH 18/20] =?UTF-8?q?=E4=BB=93=E5=BA=93=E7=89=A9=E6=96=99?= =?UTF-8?q?=E8=A1=A8=E5=92=8C=E7=89=A9=E6=96=99=E6=89=B9=E6=AC=A1=E8=A1=A8?= =?UTF-8?q?count=5F=5Fgt=3D0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/views.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index 109feb6..0956d4f 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -39,7 +39,7 @@ class InventoryViewSet(ListModelMixin, GenericViewSet): 仓库物料表 """ perms_map = {'*': '*'} - queryset = Inventory.objects.select_related('material', 'warehouse').all() + queryset = Inventory.objects.select_related('material', 'warehouse').filter(count__gt=0).all() serializer_class = InventorySerializer filterset_fields = ['material', 'warehouse'] search_fields = [] @@ -48,7 +48,7 @@ class InventoryViewSet(ListModelMixin, GenericViewSet): class MaterialBatchViewSet(ListModelMixin, GenericViewSet): perms_map = {'*': '*'} - queryset = MaterialBatch.objects.select_related('material', 'warehouse').all() + queryset = MaterialBatch.objects.select_related('material', 'warehouse').filter(count__gt=0).all() serializer_class = MaterialBatchSerializer # filterset_fields = ['material', 'warehouse'] filterset_class = MbFilterSet From cdc4d4acafb8790cca76f1ec1db7f03830ec3df2 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 16:46:37 +0800 Subject: [PATCH 19/20] update_subplan_main bug --- hb_server/apps/pm/signals.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/pm/signals.py b/hb_server/apps/pm/signals.py index e5cc595..c4871ee 100644 --- a/hb_server/apps/pm/signals.py +++ b/hb_server/apps/pm/signals.py @@ -23,8 +23,8 @@ def update_subplan_main(sender, instance, created, **kwargs): if subplan.main_product.type == Material.MA_TYPE_GOOD: # 如果是产品,更新主计划进度 plan = subplan.production_plan - plan.count_real = subplan.count_real - plan.count_ok = subplan.count_ok + plan.count_real = subplan.main_count_real + plan.count_ok = subplan.main_count_ok plan.save() From ded0e2e61ef25592e6bb528acc4f59baae6f77d5 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 15 Dec 2021 17:23:08 +0800 Subject: [PATCH 20/20] =?UTF-8?q?operation=20record=20update=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 3a674e7..d426947 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -614,7 +614,7 @@ class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, instance.delete() return Response() -class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): +class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet): """ 操作使用的自定义表格 """ @@ -625,6 +625,10 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): ordering_fields = ['id'] ordering = ['-id'] + def get_serializer_class(self): + if self.action == 'update': + return OperationRecordSubmitSerializer + return super().get_serializer_class() @transaction.atomic() def destroy(self, request, *args, **kwargs): instance = self.get_object() @@ -643,12 +647,14 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): # 后续加入系统带入数据 return Response(data) - @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}) + + def update(self, request, *args, **kwargs): + serializer = OperationRecordSubmitSerializer(data=request.data) serializer.is_valid(raise_exception=True) vdata = serializer.validated_data opr = self.get_object() + if opr.operation.is_submited: + raise exceptions.APIException('操作已提交不可修改') wrds = [] for m in vdata['record_data']: # 保存记录详情 form_field = m['form_field']