From 306f916f0019d3da2b6e60e056a8fdb493c14490 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 7 Dec 2021 16:26:59 +0800 Subject: [PATCH 01/13] salecreate validate product --- hb_server/apps/sam/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hb_server/apps/sam/serializers.py b/hb_server/apps/sam/serializers.py index eb3a840..e00b9cb 100644 --- a/hb_server/apps/sam/serializers.py +++ b/hb_server/apps/sam/serializers.py @@ -72,7 +72,7 @@ class SaleCreateSerializer(serializers.ModelSerializer): attrs['customer'] = order.customer attrs['product'] = order.product for i in attrs['iproducts']: - if i.material is not attrs['product']: + if i.material != attrs['product']: raise exceptions.APIException('产品选取错误') return super().validate(attrs) From bf3a7080b2d9df1c025a562b7d84baf7f863c1ab Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 8 Dec 2021 11:31:15 +0800 Subject: [PATCH 02/13] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=B9=E5=B1=82?= =?UTF-8?q?=E6=A3=80=E9=AA=8C?= 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/inm/models.py | 3 +++ hb_server/apps/inm/serializers.py | 8 ++++++- hb_server/apps/inm/views.py | 19 ++++++++++++++-- hb_server/apps/qm/models.py | 2 ++ hb_server/apps/sam/models.py | 2 -- hb_server/apps/sam/serializers.py | 7 +----- hb_server/apps/sam/views.py | 37 ++++++++++++------------------- hb_server/apps/wpm/models.py | 2 ++ hb_server/apps/wpm/views.py | 28 ++++++++++++++--------- 10 files changed, 65 insertions(+), 45 deletions(-) diff --git a/hb_server/apps/inm/filters.py b/hb_server/apps/inm/filters.py index 3f550a3..2ff12aa 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'] \ No newline at end of file + fields = ['material', 'warehouse', 'batch', 'order', 'is_mtested', 'is_mtestok'] \ No newline at end of file diff --git a/hb_server/apps/inm/models.py b/hb_server/apps/inm/models.py index 9059a91..10248cd 100644 --- a/hb_server/apps/inm/models.py +++ b/hb_server/apps/inm/models.py @@ -93,6 +93,9 @@ class IProduct(BaseModel): warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库') batch = models.CharField('所属批次号', max_length=100, default='') wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True) + is_mtested = models.BooleanField('是否军检', default=False) + is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True) + remark_mtest = models.TextField('军检备注', null=True, blank=True) is_saled = models.BooleanField('是否售出', default=False) class FIFOItemProduct(BaseModel): diff --git a/hb_server/apps/inm/serializers.py b/hb_server/apps/inm/serializers.py index 7f050fc..eb94f33 100644 --- a/hb_server/apps/inm/serializers.py +++ b/hb_server/apps/inm/serializers.py @@ -146,4 +146,10 @@ class InmTestRecordCreateSerializer(serializers.ModelSerializer): is_testok = serializers.BooleanField() class Meta: model = TestRecord - fields = ['form', 'record_data', 'is_testok', 'fifo_item'] \ No newline at end of file + fields = ['form', 'record_data', 'is_testok', 'fifo_item'] + + +class IProductMtestSerializer(serializers.ModelSerializer): + class Meta: + model = IProduct + fields = ['remark_mtest', 'is_mtestok'] \ No newline at end of file diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index 8f455e0..eb49a70 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -1,12 +1,13 @@ from django.shortcuts import render from rest_framework import serializers +from rest_framework import exceptions from rest_framework.exceptions import APIException from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveModelMixin from rest_framework.viewsets import GenericViewSet, ModelViewSet from apps.inm.filters import IProductFilterSet, MbFilterSet from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory -from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer +from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, IProductMtestSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer from apps.inm.signals import update_inm from apps.qm.models import TestRecordItem from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin @@ -172,4 +173,18 @@ class IProductViewSet(ListModelMixin, GenericViewSet): filterset_class = IProductFilterSet search_fields = [] ordering_fields = ['create_time'] - ordering = ['-create_time'] \ No newline at end of file + ordering = ['-create_time'] + + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=IProductMtestSerializer) + def mtest(self, request, pk=None): + """ + 军检 + """ + obj = self.get_object() + if obj.is_mtested: + raise exceptions.APIException('已进行军检') + obj.remark_mtest = request.data.get('remark_mtest', None) + obj.is_mtested = True + obj.is_mtestok = request.data.get('is_mtestok') + obj.save() + return Response() \ No newline at end of file diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index eca8ed5..1063f81 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -50,11 +50,13 @@ class TestRecord(CommonAModel): TEST_STEP = 10 TEST_PROCESS = 20 TEST_PROCESS_RE = 30 + TEST_COMB = 36 TEST_FINAL = 40 type_choice = ( (TEST_STEP, '子工序检验'), (TEST_PROCESS, '工序检验'), (TEST_PROCESS_RE, '工序复检'), + (TEST_COMB, '夹层检验'), (TEST_FINAL, '成品检验') ) form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE) diff --git a/hb_server/apps/sam/models.py b/hb_server/apps/sam/models.py index e82137a..3e51a97 100644 --- a/hb_server/apps/sam/models.py +++ b/hb_server/apps/sam/models.py @@ -89,8 +89,6 @@ class SaleProduct(BaseModel): sale = models.ForeignKey(Sale, verbose_name='关联销售记录', on_delete=models.CASCADE) number = models.CharField('物品编号', max_length=50) iproduct = models.ForeignKey('inm.iproduct', verbose_name='关联库存产品', on_delete=models.CASCADE, related_name='sale_iproduct') - is_mtested = models.BooleanField('是否军检', default=False) - is_mtestok = models.BooleanField('是否军检合格', null=True, blank=True) remark = models.TextField('备注', null=True, blank=True) class Meta: diff --git a/hb_server/apps/sam/serializers.py b/hb_server/apps/sam/serializers.py index e00b9cb..058db28 100644 --- a/hb_server/apps/sam/serializers.py +++ b/hb_server/apps/sam/serializers.py @@ -101,9 +101,4 @@ class SaleProductCreateSerializer(serializers.ModelSerializer): instance = SaleProduct.objects.create(**validated_data) instance.sale.count = SaleProduct.objects.filter(sale=instance.sale).count() instance.sale.save() - return instance - -class SaleProductMtestSerializer(serializers.ModelSerializer): - class Meta: - model = SaleProduct - fields = ['remark', 'is_mtestok'] \ No newline at end of file + return instance \ No newline at end of file diff --git a/hb_server/apps/sam/views.py b/hb_server/apps/sam/views.py index e3098ef..10a6d97 100644 --- a/hb_server/apps/sam/views.py +++ b/hb_server/apps/sam/views.py @@ -5,7 +5,7 @@ from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModel from apps.mtm.models import Material from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse from apps.inm.signals import update_inm -from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer, SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer, SaleProductMtestSerializer +from apps.sam.serializers import ContractCreateUpdateSerializer, ContractSerializer, CustomerCreateUpdateSerializer, CustomerSerializer, OrderCreateUpdateSerializer, OrderSerializer, SaleCreateSerializer, SaleListSerializer, SaleProductCreateSerializer, SaleProductListSerializer from apps.sam.models import Contract, Customer, Order, Sale, SaleProduct from rest_framework.viewsets import GenericViewSet, ModelViewSet from apps.system.mixins import CreateUpdateCustomMixin @@ -133,13 +133,13 @@ class SaleViewSet(CreateUpdateCustomMixin, ListModelMixin, RetrieveModelMixin, C fifo.inout_date = timezone.now() fifo.create_by = request.user fifo.save() - # 出库条目 - spds = SaleProduct.objects.filter(sale=obj) - for i in spds: - if i.is_mtested and i.is_mtestok: - pass - else: - raise exceptions.APIException('存在未军检产品') + # 出库条目 暂时不校验是否军检 + # spds = SaleProduct.objects.filter(sale=obj) + # for i in spds: + # if i.is_mtested and i.is_mtestok: + # pass + # else: + # raise exceptions.APIException('存在未军检产品') # 创建出库条目 ips = IProduct.objects.filter(sale_iproduct__sale=obj) items = ips.values('warehouse', 'material', 'batch').annotate(total=Count('id')) @@ -199,21 +199,12 @@ class SaleProductViewSet(ListModelMixin, DestroyModelMixin, CreateModelMixin, Ge def destroy(self, request, *args, **kwargs): obj = self.get_object() - obj.sale.count = SaleProduct.objects.filter(sale=obj.sale).count() - obj.sale.save() + sale = obj.sale + if sale.is_audited: + raise exceptions.APIException('该销售记录已审核,不可删除产品') + sale.count = SaleProduct.objects.filter(sale=obj.sale).count() + sale.save() obj.delete() return Response() - @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=SaleProductMtestSerializer) - def mtest(self, request, pk=None): - """ - 军检 - """ - obj = self.get_object() - if obj.is_mtested: - raise exceptions.APIException('已进行军检') - obj.remark = request.data.get('remark', None) - obj.is_mtested = True - obj.is_mtestok = request.data.get('is_mtestok') - obj.save() - return Response() \ No newline at end of file + \ No newline at end of file diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index b21c765..93fca95 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -28,6 +28,7 @@ class WProduct(CommonAModel): WPR_ACT_STATE_DOWAIT = 8 WPR_ACT_STATE_DOING = 10 WPR_ACT_STATE_TOTEST = 20 + WPR_ACT_STATE_TOCOMBTEST = 26 WPR_ACT_STATE_OK = 30 WPR_ACT_STATE_INM = 40 WPR_ACT_STATE_NOTOK = 50 @@ -37,6 +38,7 @@ class WProduct(CommonAModel): (WPR_ACT_STATE_DOWAIT, '操作准备中'), (WPR_ACT_STATE_DOING, '操作进行中'), (WPR_ACT_STATE_TOTEST, '待检验'), + (WPR_ACT_STATE_TOCOMBTEST, '待夹层检验'), (WPR_ACT_STATE_OK, '已合格'), (WPR_ACT_STATE_INM, '库存中'), (WPR_ACT_STATE_NOTOK, '不合格'), diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 40b4b93..eb6a25d 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -195,7 +195,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): record_data = vdata.pop('record_data') wproduct = vdata['wproduct'] if wproduct.act_state not in [WProduct.WPR_ACT_STATE_TOTEST, - WProduct.WPR_ACT_STATE_TORETEST, WProduct.WPR_ACT_STATE_TOFINALTEST]: + 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('未填写检测结论') @@ -206,6 +206,8 @@ class WProductViewSet(ListModelMixin, GenericViewSet): savedict['type'] = TestRecord.TEST_PROCESS_RE elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOFINALTEST: savedict['type'] = TestRecord.TEST_FINAL + elif wproduct.act_state == WProduct.WPR_ACT_STATE_TOCOMBTEST: + savedict['type'] = TestRecord.TEST_COMB obj = serializer.save(**savedict) tris = [] for m in record_data: # 保存记录详情 @@ -224,10 +226,12 @@ class WProductViewSet(ListModelMixin, GenericViewSet): # 如果检测合格, 变更动态产品进行状态 if obj.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 # 成品检验 + 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 + elif wproduct.step.type == Step.STEP_TYPE_COMB: # 如果是夹层 + wproduct.act_state = WProduct.WPR_ACT_STATE_TOCOMBTEST else: wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.number is None: # 产生半成品编号 @@ -498,25 +502,29 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd for x in range(i.count): WProduct.objects.create(**wpr) elif step.type == Step.STEP_TYPE_COMB: - if i.subproduction_progress.is_main: + oms_w = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT, + subproduction_progress__ismain=True) + if len(oms_w) == 1: newstep, hasNext = WpmServies.get_next_step(i.subproduction_plan, step) + oms_w = oms_w[0] wproduct = WProduct() - wproduct.material = i.material + wproduct.material = oms_w.material wproduct.step = newstep - wproduct.subproduction_plan = i.subproduction_plan + wproduct.subproduction_plan = oms_w.subproduction_plan if hasNext: wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT else: wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST # 更新子计划进度 - instance = SubProductionProgress.objects.get(subproduction_plan=i.subproduction_plan, - is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) + instance = oms_w.subproduction_progress instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨 instance.save() wproduct.save() # 隐藏原半成品 wps = WProduct.objects.filter(ow_wproduct__operation = op) wps.update(is_hidden=True, child=wproduct) + else: + raise exceptions.APIException('产出物料错误') op.is_submited = True op.save() return Response() From f9784e244d821dab3d89cf7e03476efc5c5d5a01 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 8 Dec 2021 14:08:00 +0800 Subject: [PATCH 03/13] =?UTF-8?q?=E5=BA=93=E5=AD=98=E4=BA=A7=E5=93=81?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=86=9B=E6=A3=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/models.py | 12 +++++++++++- hb_server/apps/wpm/views.py | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index 5d39027..8cdde3a 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -130,6 +130,16 @@ class RecordFormField(CommonAModel): """ 记录字段表 """ + FIELD_STRING = 'string' + FIELD_INT = 'int' + FIELD_FLOAT = 'float' + FIELD_BOOL = 'boolean' + FIELD_DATE = 'date' + FIELD_TIME = 'time' + FIELD_DATETIME = 'datetime' + FIELD_RADIO = 'radio' + FIELD_CHECKBOX = 'checkbox' + FIELD_SELECT = 'select' field_type_choices = ( ('string', '字符串'), ('int', '整型'), @@ -143,7 +153,7 @@ class RecordFormField(CommonAModel): ('select', '单选下拉'), ('selects', '多选下拉'), ('textarea', '文本域'), - ('draw', '绘图') + ('draw', '绘图'), ) high_rule_choices = ( (1, '小于'), diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index eb6a25d..b4160b4 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -505,8 +505,9 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd oms_w = OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT, subproduction_progress__ismain=True) if len(oms_w) == 1: - newstep, hasNext = WpmServies.get_next_step(i.subproduction_plan, step) oms_w = oms_w[0] + # 校验单片数量是否正确, 暂时未写 + newstep, hasNext = WpmServies.get_next_step(oms_w.subproduction_plan, step) wproduct = WProduct() wproduct.material = oms_w.material wproduct.step = newstep From 90802f418f72b22b8edf654f7f17cd51e111e3b4 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 8 Dec 2021 14:09:03 +0800 Subject: [PATCH 04/13] =?UTF-8?q?=E5=A4=B9=E5=B1=82=E6=A3=80=E6=B5=8B?= =?UTF-8?q?=E5=92=8C=E5=86=9B=E6=A3=80=E6=95=B0=E6=8D=AE=E5=BA=93=E6=9B=B4?= =?UTF-8?q?=E6=94=B9=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../inm/migrations/0022_auto_20211208_1408.py | 28 +++++++++++++++++++ .../migrations/0014_alter_testrecord_type.py | 18 ++++++++++++ .../sam/migrations/0010_auto_20211208_1408.py | 21 ++++++++++++++ .../0030_alter_wproduct_act_state.py | 18 ++++++++++++ 4 files changed, 85 insertions(+) create mode 100644 hb_server/apps/inm/migrations/0022_auto_20211208_1408.py create mode 100644 hb_server/apps/qm/migrations/0014_alter_testrecord_type.py create mode 100644 hb_server/apps/sam/migrations/0010_auto_20211208_1408.py create mode 100644 hb_server/apps/wpm/migrations/0030_alter_wproduct_act_state.py diff --git a/hb_server/apps/inm/migrations/0022_auto_20211208_1408.py b/hb_server/apps/inm/migrations/0022_auto_20211208_1408.py new file mode 100644 index 0000000..80db224 --- /dev/null +++ b/hb_server/apps/inm/migrations/0022_auto_20211208_1408.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.9 on 2021-12-08 06:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inm', '0021_fifoitemproduct_iproduct'), + ] + + operations = [ + migrations.AddField( + model_name='iproduct', + name='is_mtested', + field=models.BooleanField(default=False, verbose_name='是否军检'), + ), + migrations.AddField( + model_name='iproduct', + name='is_mtestok', + field=models.BooleanField(blank=True, null=True, verbose_name='是否军检合格'), + ), + migrations.AddField( + model_name='iproduct', + name='remark_mtest', + field=models.TextField(blank=True, null=True, verbose_name='军检备注'), + ), + ] diff --git a/hb_server/apps/qm/migrations/0014_alter_testrecord_type.py b/hb_server/apps/qm/migrations/0014_alter_testrecord_type.py new file mode 100644 index 0000000..c280a58 --- /dev/null +++ b/hb_server/apps/qm/migrations/0014_alter_testrecord_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-12-08 06:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0013_auto_20211202_1620'), + ] + + operations = [ + migrations.AlterField( + model_name='testrecord', + name='type', + field=models.PositiveSmallIntegerField(choices=[(10, '子工序检验'), (20, '工序检验'), (30, '工序复检'), (36, '夹层检验'), (40, '成品检验')], default=20), + ), + ] diff --git a/hb_server/apps/sam/migrations/0010_auto_20211208_1408.py b/hb_server/apps/sam/migrations/0010_auto_20211208_1408.py new file mode 100644 index 0000000..d262ae2 --- /dev/null +++ b/hb_server/apps/sam/migrations/0010_auto_20211208_1408.py @@ -0,0 +1,21 @@ +# Generated by Django 3.2.9 on 2021-12-08 06:08 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('sam', '0009_alter_saleproduct_is_mtestok'), + ] + + operations = [ + migrations.RemoveField( + model_name='saleproduct', + name='is_mtested', + ), + migrations.RemoveField( + model_name='saleproduct', + name='is_mtestok', + ), + ] diff --git a/hb_server/apps/wpm/migrations/0030_alter_wproduct_act_state.py b/hb_server/apps/wpm/migrations/0030_alter_wproduct_act_state.py new file mode 100644 index 0000000..9329207 --- /dev/null +++ b/hb_server/apps/wpm/migrations/0030_alter_wproduct_act_state.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.9 on 2021-12-08 06:08 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0029_auto_20211202_1630'), + ] + + operations = [ + migrations.AlterField( + model_name='wproduct', + name='act_state', + field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '库存中'), (50, '不合格'), (60, '待成品检验')], default=0, verbose_name='进行状态'), + ), + ] From cd3d7b7d182e99e9211fa7e7632327c15017f853 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 8 Dec 2021 14:43:22 +0800 Subject: [PATCH 05/13] =?UTF-8?q?=E6=89=B9=E9=87=8F=E5=85=A5=E5=BA=93bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/models.py | 4 ++++ hb_server/apps/wpm/views.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index 8cdde3a..d4b20d2 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -140,6 +140,10 @@ class RecordFormField(CommonAModel): FIELD_RADIO = 'radio' FIELD_CHECKBOX = 'checkbox' FIELD_SELECT = 'select' + FIELD_SELECTS = 'selects' + FIELD_TEXTAREA = 'textarea' + FIELD_DRAW = 'draw' + FIELD_FROMSYSTEM = 'fromsystem' field_type_choices = ( ('string', '字符串'), ('int', '整型'), diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index b4160b4..bcc507a 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -276,7 +276,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): fifoitem.is_tested = True fifoitem.is_testok = True fifoitem.warehouse = warehouse - fifoitem.material = i['material'] + fifoitem.material = Material.objects.get(pk=i['material']) fifoitem.count = i['total'] fifoitem.batch = spi.number fifoitem.fifo = fifo From f27a9e8f9239599178e351f523fcfdeadeff744a Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 8 Dec 2021 14:45:32 +0800 Subject: [PATCH 06/13] =?UTF-8?q?=E6=89=B9=E9=87=8F=E5=85=A5=E5=BA=93bug?= 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 bcc507a..1eff791 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -271,7 +271,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark) # 创建入库明细 for i in wproducts_a: - spi = i['subproduction_plan'] + spi = SubProductionPlan.objects.get(pk=i['subproduction_plan']) fifoitem = FIFOItem() fifoitem.is_tested = True fifoitem.is_testok = True From 752a0e9d92720b89507368759a240cc524eb6e03 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 8 Dec 2021 14:48:55 +0800 Subject: [PATCH 07/13] =?UTF-8?q?=E5=A4=B9=E5=B1=82=E6=A3=80=E9=AA=8C?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E4=B8=BA=E5=90=88=E6=A0=BC?= 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, 2 deletions(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 1eff791..a9a9230 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -230,8 +230,6 @@ class WProductViewSet(ListModelMixin, GenericViewSet): 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 - elif wproduct.step.type == Step.STEP_TYPE_COMB: # 如果是夹层 - wproduct.act_state = WProduct.WPR_ACT_STATE_TOCOMBTEST else: wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.number is None: # 产生半成品编号 From 9c287399b7965050b8491ffcc42d899a11cca536 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 9 Dec 2021 13:59:28 +0800 Subject: [PATCH 08/13] =?UTF-8?q?=E6=93=8D=E4=BD=9C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E6=89=B9=E9=87=8F=E8=BE=93=E5=85=A5=E8=BE=93=E5=87=BA=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/views.py | 4 +++ hb_server/apps/qm/models.py | 2 +- hb_server/apps/wpm/models.py | 15 ++++++-- hb_server/apps/wpm/serializers.py | 18 +++++++++- hb_server/apps/wpm/views.py | 57 ++++++++++++++++++++++++++++--- 5 files changed, 86 insertions(+), 10 deletions(-) diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index eb49a70..5ef42dc 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -9,6 +9,7 @@ from apps.inm.filters import IProductFilterSet, MbFilterSet from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, IProductListSerializer, IProductMtestSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer from apps.inm.signals import update_inm +from apps.mtm.models import Material from apps.qm.models import TestRecordItem from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action @@ -183,6 +184,9 @@ class IProductViewSet(ListModelMixin, GenericViewSet): obj = self.get_object() if obj.is_mtested: raise exceptions.APIException('已进行军检') + if obj.wproduct: + if obj.wproduct.material.type != Material.MA_TYPE_GOOD: + raise exceptions.APIException('军检必须是成品') obj.remark_mtest = request.data.get('remark_mtest', None) obj.is_mtested = True obj.is_mtestok = request.data.get('is_mtestok') diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index 1063f81..f769335 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -69,7 +69,7 @@ class TestRecord(CommonAModel): step = models.ForeignKey('mtm.step', 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) - test_record = models.ForeignKey('self', verbose_name='关联检验记录', on_delete=models.CASCADE, null=True, blank=True) + test_record = models.ForeignKey('self', verbose_name='关联的检验记录', on_delete=models.CASCADE, null=True, blank=True) remark = models.TextField('备注', default='') diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 93fca95..9ce228a 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -9,7 +9,6 @@ from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organi from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords 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): """ @@ -40,7 +39,7 @@ class WProduct(CommonAModel): (WPR_ACT_STATE_TOTEST, '待检验'), (WPR_ACT_STATE_TOCOMBTEST, '待夹层检验'), (WPR_ACT_STATE_OK, '已合格'), - (WPR_ACT_STATE_INM, '库存中'), + (WPR_ACT_STATE_INM, '已入库'), (WPR_ACT_STATE_NOTOK, '不合格'), (WPR_ACT_STATE_TOFINALTEST, '待成品检验') ) @@ -57,6 +56,16 @@ class WProduct(CommonAModel): operation = models.ForeignKey('wpm.operation', verbose_name='关联操作', on_delete=models.SET_NULL, null=True, blank=True, related_name='wp_operation') +class WprouctTicket(CommonAModel): + """ + 玻璃审批工单 + """ + number = models.CharField('物品编号', null=True, blank=True, max_length=50) + wproduct = models.ForeignKey(WProduct, verbose_name='关联产品', on_delete=models.CASCADE) + 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) class Pick(CommonADModel): """ @@ -110,7 +119,7 @@ class OperationMaterial(BaseModel): operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE) material = models.ForeignKey(Material, verbose_name='可能产出的产品', on_delete=models.CASCADE, null=True, blank=True) - count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)], null=True, blank=True) + count = models.PositiveSmallIntegerField('消耗或产出数量', null=True, blank=True) 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) diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index b689a84..9c150f7 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -292,6 +292,11 @@ class WpmTestRecordCreateSerializer(serializers.ModelSerializer): model = TestRecord fields = ['form', 'record_data', 'is_testok', 'wproduct'] +class WpmTestFormInitSerializer(serializers.Serializer): + wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True) + form = serializers.PrimaryKeyRelatedField(queryset=RecordForm.objects.all(), required=True) + + class WplanPutInSerializer(serializers.Serializer): warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") remark = serializers.CharField(label="入库备注", required =False) @@ -335,6 +340,11 @@ class OperationMaterialCreate1Serailizer(serializers.ModelSerializer): class Meta: model = OperationMaterial fields = ['operation', 'wmaterial', 'count'] + + def validate(self, attrs): + if attrs['count'] <=0: + raise exceptions.APIException('消耗物料数量错误') + return super().validate(attrs) def create(self, validated_data): wmaterial = validated_data['wmaterial'] @@ -343,7 +353,10 @@ class OperationMaterialCreate1Serailizer(serializers.ModelSerializer): validated_data['batch'] = wmaterial.batch validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_IN return super().create(validated_data) - + +class OperationMaterialCreate1ListSerailizer(serializers.ListSerializer): + child=OperationMaterialCreate1Serailizer() + class OperationMaterialCreate2Serailizer(serializers.ModelSerializer): subproduction_progress = serializers.PrimaryKeyRelatedField(required=True, queryset=SubProductionProgress.objects.all()) class Meta: @@ -357,6 +370,9 @@ class OperationMaterialCreate2Serailizer(serializers.ModelSerializer): validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_OUT return super().create(validated_data) + +class OperationMaterialCreate2ListSerailizer(serializers.ListSerializer): + child=OperationMaterialCreate2Serailizer() class OperationMaterialCreate3Serializer(serializers.ModelSerializer): material = serializers.PrimaryKeyRelatedField(required=True, queryset=Material.objects.all()) class Meta: diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index a9a9230..717a2d3 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -18,7 +18,7 @@ from rest_framework.decorators import action from apps.wpm.filters import WMaterialFilterSet from apps.wpm.models import OperationEquip, OperationWproduct, Pick, PickWproduct, 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, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer +from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1ListSerailizer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2ListSerailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickHalfsSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestFormInitSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer, WproductPutInsSerializer from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers @@ -183,6 +183,22 @@ class WProductViewSet(ListModelMixin, GenericViewSet): ordering_fields = ['id'] ordering = ['id'] + @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestFormInitSerializer) + def test_init(self, request, pk=None): + """ + 检验表单初始化 + """ + serializer = WpmTestFormInitSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.validated_data + wproduct = vdata['wproduct'] + form = vdata['form'] + data = RecordFormDetailSerializer(instance=form).data + # 后续加入系统带入数据 + # 如果是复检记录, 需要带入原数据 + + return Response(data) + @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer) @transaction.atomic def test(self, request, pk=None): @@ -227,7 +243,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): if obj.is_testok: if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: # 复检 - wproduct.act_state = WProduct.WPR_ACT_STATE_DOWAIT + 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: @@ -244,7 +260,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): else:# 如果不合格 wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK wproduct.save() - + # 需要走不合格品审理单 return Response() @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer) @@ -601,6 +617,16 @@ class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): instance.delete() return Response() + @action(methods=['get'], detail=True, perms_map={'get':'*'}) + def init(self, request, pk=None): + ''' + 表格初始化 + ''' + obj = self.get_object() + data = RecordFormDetailSerializer(instance=obj.form).data + # 后续加入系统带入数据 + 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}) @@ -639,7 +665,18 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod if self.action == 'create': return OperationMaterialCreate1Serailizer return super().get_serializer_class() - + + @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=OperationMaterialCreate1ListSerailizer) + def creates(self, request, pk=None): + """ + 批量创建消耗物料 + """ + serializer = OperationMaterialCreate1ListSerailizer(data=request.data, many=True) + serializer.is_valid(raise_exception=True) + serializer.save() + return Response() + + @transaction.atomic() def destroy(self, request, *args, **kwargs): instance = self.get_object() @@ -663,7 +700,17 @@ class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyMo if self.action == 'create': return OperationMaterialCreate2Serailizer return super().get_serializer_class() - + + @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=OperationMaterialCreate2ListSerailizer) + def creates(self, request, pk=None): + """ + 批量创建产出物料 + """ + serializer = OperationMaterialCreate2ListSerailizer(data=request.data, many=True) + serializer.is_valid(raise_exception=True) + serializer.save() + return Response() + @transaction.atomic() def destroy(self, request, *args, **kwargs): instance = self.get_object() From fea32171f90797d2c9087070444df81182843288 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 9 Dec 2021 14:05:01 +0800 Subject: [PATCH 09/13] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD?= 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 8b07565..3707a45 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 develop') + ret = os.popen('git pull https://caoqianming%40foxmail.com:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git develop') # 打包前端 # os.chdir('/home/hberp/hb_client') # os.system('npm run build:prod') From 30fb6749bb224404ca1b0aeb83a8fa8e849204fa Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 9 Dec 2021 15:30:21 +0800 Subject: [PATCH 10/13] =?UTF-8?q?=E6=8A=80=E6=9C=AF=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=AD=9B=E9=80=89=E6=9D=A1=E4=BB=B6operation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/filters.py | 15 +++++++++++++++ hb_server/apps/mtm/views.py | 3 ++- hb_server/apps/wf/models.py | 2 +- hb_server/apps/wpm/models.py | 2 +- hb_server/apps/wpm/views.py | 27 ++++++++++++++++++++------- 5 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 hb_server/apps/mtm/filters.py diff --git a/hb_server/apps/mtm/filters.py b/hb_server/apps/mtm/filters.py new file mode 100644 index 0000000..b4a2976 --- /dev/null +++ b/hb_server/apps/mtm/filters.py @@ -0,0 +1,15 @@ +from django_filters import rest_framework as filters +from apps.mtm.models import TechDoc + + + + +class TechDocFilterset(filters.FilterSet): + # operation = filters.NumberFilter(method='filter_operation') + operation = filters.NumberFilter(field_name="subproduction__subplan_subprod__ow_subplan__operation") + class Meta: + model = TechDoc + fields = ['subproduction', 'operation'] + + # def filter_operation(self, queryset, name, value): + # return queryset.filter(subproduction__subplan_subprod__ow_subplan__operation=value) diff --git a/hb_server/apps/mtm/views.py b/hb_server/apps/mtm/views.py index 2ab241c..e1c8f95 100644 --- a/hb_server/apps/mtm/views.py +++ b/hb_server/apps/mtm/views.py @@ -1,6 +1,7 @@ from django.shortcuts import render from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin +from apps.mtm.filters import TechDocFilterset from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc, UsedStep, SubProduction from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormDetailSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, SubprodctionMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer @@ -201,7 +202,7 @@ class TechDocViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet): """ perms_map = {'*':'*'} queryset = TechDoc.objects.select_related('file').all() - filterset_fields = ['subproduction'] + filterset_class = TechDocFilterset search_fields = ['name'] ordering = ['-id'] diff --git a/hb_server/apps/wf/models.py b/hb_server/apps/wf/models.py index bc1597c..4d06ca1 100644 --- a/hb_server/apps/wf/models.py +++ b/hb_server/apps/wf/models.py @@ -210,7 +210,7 @@ class Ticket(CommonBModel): participant = models.JSONField('当前处理人', default=list, blank=True, help_text='可以为空(无处理人的情况,如结束状态)、userid、userid列表') act_state = models.IntegerField('进行状态', default=1, help_text='当前工单的进行状态', choices=act_state_choices) multi_all_person = models.JSONField('全部处理的结果', default=dict, blank=True, help_text='需要当前状态处理人全部处理时实际的处理结果,json格式') - + # class TicketCustomField(BaseModel): # """ diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 9ce228a..391b591 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -108,7 +108,7 @@ class OperationWproduct(BaseModel): 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) + subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='ow_subplan') class OperationMaterial(BaseModel): diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 717a2d3..9db3504 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -12,6 +12,7 @@ from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMateria from apps.pm.models import SubProductionPlan, SubProductionProgress from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from apps.qm.models import TestRecord, TestRecordItem +from apps.qm.serializers import TestRecordDetailSerializer from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action @@ -193,10 +194,20 @@ class WProductViewSet(ListModelMixin, GenericViewSet): vdata = serializer.validated_data wproduct = vdata['wproduct'] form = vdata['form'] - data = RecordFormDetailSerializer(instance=form).data - # 后续加入系统带入数据 - # 如果是复检记录, 需要带入原数据 + + # 如果是复检记录, 需要带入原数据 + if wproduct.act_state == WProduct.WPR_ACT_STATE_TORETEST: + # 查找最近一条检验记录 + trs = TestRecord.objects.filter(wproduct=wproduct, type=TestRecord.TEST_PROCESS).order_by('-id').first() + if trs: + origin_data = TestRecordDetailSerializer() + else: + raise exceptions.APIException('原工序检验记录不存在') + else: + data = RecordFormDetailSerializer(instance=form).data + + # 后续加入系统自带数据 return Response(data) @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer) @@ -250,7 +261,6 @@ class WProductViewSet(ListModelMixin, GenericViewSet): wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.number is None: # 产生半成品编号 wproduct.number = 'WP'+ranstr(7) - wproduct.save() # 更新子计划状态 # 更新子计划主产品数 instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, @@ -259,8 +269,9 @@ class WProductViewSet(ListModelMixin, GenericViewSet): instance.save() else:# 如果不合格 wproduct.act_state = WProduct.WPR_ACT_STATE_NOTOK - wproduct.save() # 需要走不合格品审理单 + wproduct.update_by = request.user + wproduct.save() return Response() @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WproductPutInsSerializer) @@ -310,7 +321,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): FIFOItemProduct.objects.bulk_create(ips) # 更新库存并修改半成品进行状态 update_inm(fifo) - wproducts.update(act_state=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user) + wproducts.update(act_state=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user, update_time=timezone.now()) return Response() @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer) @@ -504,6 +515,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨 instance.save() wp.operation = None + wp.update_by = request.user wp.save() elif step.type == Step.STEP_TYPE_DIV: # 更新物料产出情况 @@ -534,10 +546,11 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd instance = oms_w.subproduction_progress instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨 instance.save() + wproduct.create_by = request.user wproduct.save() # 隐藏原半成品 wps = WProduct.objects.filter(ow_wproduct__operation = op) - wps.update(is_hidden=True, child=wproduct) + wps.update(is_hidden=True, child=wproduct, update_by=request.user, update_time=timezone.now()) else: raise exceptions.APIException('产出物料错误') op.is_submited = True From 590059b23f5bc9b70e3462f58dace5f79740e3e4 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 9 Dec 2021 16:06:54 +0800 Subject: [PATCH 11/13] =?UTF-8?q?=E8=BE=93=E5=87=BA=E8=BE=93=E5=87=BA?= =?UTF-8?q?=E7=89=A9=E6=96=99=E6=89=B9=E9=87=8F=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/filters.py | 2 +- hb_server/apps/pm/models.py | 2 ++ hb_server/apps/pm/signals.py | 10 +++++++++- hb_server/apps/wpm/views.py | 4 ++-- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/hb_server/apps/mtm/filters.py b/hb_server/apps/mtm/filters.py index b4a2976..6f6b28b 100644 --- a/hb_server/apps/mtm/filters.py +++ b/hb_server/apps/mtm/filters.py @@ -6,7 +6,7 @@ from apps.mtm.models import TechDoc class TechDocFilterset(filters.FilterSet): # operation = filters.NumberFilter(method='filter_operation') - operation = filters.NumberFilter(field_name="subproduction__subplan_subprod__ow_subplan__operation") + operation = filters.CharFilter(field_name="subproduction__subplan_subprod__ow_subplan__operation") class Meta: model = TechDoc fields = ['subproduction', 'operation'] diff --git a/hb_server/apps/pm/models.py b/hb_server/apps/pm/models.py index 9cdd6c1..6a06c29 100644 --- a/hb_server/apps/pm/models.py +++ b/hb_server/apps/pm/models.py @@ -18,6 +18,8 @@ class ProductionPlan(CommonAModel): 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) start_date = models.DateField('计划开工日期') end_date = models.DateField('计划完工日期') is_planed = models.BooleanField('是否已排产', default=False) diff --git a/hb_server/apps/pm/signals.py b/hb_server/apps/pm/signals.py index e1876a9..e5cc595 100644 --- a/hb_server/apps/pm/signals.py +++ b/hb_server/apps/pm/signals.py @@ -1,5 +1,6 @@ from django.db.models.signals import post_save from django.dispatch import receiver +from apps.mtm.models import Material from apps.pm.models import SubProductionPlan, SubProductionProgress @receiver(post_save, sender=SubProductionProgress) @@ -18,6 +19,13 @@ def update_subplan_main(sender, instance, created, **kwargs): subplan.state = SubProductionPlan.SUBPLAN_STATE_DONE elif instance.count_ok < instance.count and instance.count_ok > 0: subplan.state = SubProductionPlan.SUBPLAN_STATE_WORKING - subplan.save() + subplan.save() + 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.save() + diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 9db3504..c5e78ac 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -684,7 +684,7 @@ class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyMod """ 批量创建消耗物料 """ - serializer = OperationMaterialCreate1ListSerailizer(data=request.data, many=True) + serializer = OperationMaterialCreate1ListSerailizer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response() @@ -719,7 +719,7 @@ class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyMo """ 批量创建产出物料 """ - serializer = OperationMaterialCreate2ListSerailizer(data=request.data, many=True) + serializer = OperationMaterialCreate2ListSerailizer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save() return Response() From 65e6ee21fc38cec05ab7bbcd9ef559f145b5672f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Thu, 9 Dec 2021 16:39:13 +0800 Subject: [PATCH 12/13] =?UTF-8?q?=E5=AD=90=E8=AE=A1=E5=88=92=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0count=5Freal=20count=5Fok=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pm/migrations/0016_auto_20211209_1638.py | 23 ++++++++ .../0015_alter_testrecord_test_record.py | 19 +++++++ .../wpm/migrations/0031_auto_20211209_1638.py | 55 +++++++++++++++++++ hb_server/apps/wpm/views.py | 7 +++ 4 files changed, 104 insertions(+) create mode 100644 hb_server/apps/pm/migrations/0016_auto_20211209_1638.py create mode 100644 hb_server/apps/qm/migrations/0015_alter_testrecord_test_record.py create mode 100644 hb_server/apps/wpm/migrations/0031_auto_20211209_1638.py diff --git a/hb_server/apps/pm/migrations/0016_auto_20211209_1638.py b/hb_server/apps/pm/migrations/0016_auto_20211209_1638.py new file mode 100644 index 0000000..c6b3bfc --- /dev/null +++ b/hb_server/apps/pm/migrations/0016_auto_20211209_1638.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.9 on 2021-12-09 08:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0015_auto_20211122_1556'), + ] + + operations = [ + migrations.AddField( + model_name='productionplan', + name='count_ok', + field=models.IntegerField(default=0, verbose_name='合格数'), + ), + migrations.AddField( + model_name='productionplan', + name='count_real', + field=models.IntegerField(default=0, verbose_name='实际产出数'), + ), + ] diff --git a/hb_server/apps/qm/migrations/0015_alter_testrecord_test_record.py b/hb_server/apps/qm/migrations/0015_alter_testrecord_test_record.py new file mode 100644 index 0000000..6dfdb97 --- /dev/null +++ b/hb_server/apps/qm/migrations/0015_alter_testrecord_test_record.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.9 on 2021-12-09 08:38 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('qm', '0014_alter_testrecord_type'), + ] + + operations = [ + migrations.AlterField( + model_name='testrecord', + name='test_record', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='qm.testrecord', verbose_name='关联的检验记录'), + ), + ] diff --git a/hb_server/apps/wpm/migrations/0031_auto_20211209_1638.py b/hb_server/apps/wpm/migrations/0031_auto_20211209_1638.py new file mode 100644 index 0000000..378fe4a --- /dev/null +++ b/hb_server/apps/wpm/migrations/0031_auto_20211209_1638.py @@ -0,0 +1,55 @@ +# Generated by Django 3.2.9 on 2021-12-09 08:38 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('wf', '0017_auto_20211203_1501'), + ('pm', '0016_auto_20211209_1638'), + ('mtm', '0041_alter_material_type'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('wpm', '0030_alter_wproduct_act_state'), + ] + + operations = [ + migrations.AlterField( + model_name='operationmaterial', + name='count', + field=models.PositiveSmallIntegerField(blank=True, null=True, verbose_name='消耗或产出数量'), + ), + migrations.AlterField( + model_name='operationwproduct', + name='subproduction_plan', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ow_subplan', to='pm.subproductionplan', verbose_name='当前子生产计划'), + ), + migrations.AlterField( + model_name='wproduct', + name='act_state', + field=models.IntegerField(choices=[(6, '待复检'), (8, '操作准备中'), (10, '操作进行中'), (20, '待检验'), (26, '待夹层检验'), (30, '已合格'), (40, '已入库'), (50, '不合格'), (60, '待成品检验')], default=0, verbose_name='进行状态'), + ), + migrations.CreateModel( + name='WprouctTicket', + 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='删除标记')), + ('number', models.CharField(blank=True, max_length=50, null=True, verbose_name='物品编号')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wprouctticket_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所在物料状态')), + ('step', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='所在步骤')), + ('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='所在子生产计划')), + ('ticket', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wf.ticket', verbose_name='关联工单')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wprouctticket_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ('wproduct', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='关联产品')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index c5e78ac..6e330de 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -202,6 +202,13 @@ class WProductViewSet(ListModelMixin, GenericViewSet): trs = TestRecord.objects.filter(wproduct=wproduct, type=TestRecord.TEST_PROCESS).order_by('-id').first() if trs: origin_data = TestRecordDetailSerializer() + data = RecordFormDetailSerializer(instance=form).data + data['origin_data'] = origin_data + o_dict = {} + for i in origin_data['record_data_']: + o_dict['field_key'] = o_dict['field_value'] + for i in data['form_fields']: + i['origin_value'] = o_dict[i['field_key']] else: raise exceptions.APIException('原工序检验记录不存在') else: From 6e492529f74156529751c3328d3f70098cb3bcfc Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 10 Dec 2021 13:18:22 +0800 Subject: [PATCH 13/13] =?UTF-8?q?=E5=A4=8D=E6=A3=80=E8=A1=A8=E5=8D=95?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=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/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 6e330de..6c6b434 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -201,12 +201,12 @@ class WProductViewSet(ListModelMixin, GenericViewSet): # 查找最近一条检验记录 trs = TestRecord.objects.filter(wproduct=wproduct, type=TestRecord.TEST_PROCESS).order_by('-id').first() if trs: - origin_data = TestRecordDetailSerializer() + origin_data = TestRecordDetailSerializer(instance=trs).data data = RecordFormDetailSerializer(instance=form).data data['origin_data'] = origin_data o_dict = {} for i in origin_data['record_data_']: - o_dict['field_key'] = o_dict['field_value'] + o_dict[i['field_key']] = i['field_value'] for i in data['form_fields']: i['origin_value'] = o_dict[i['field_key']] else: