diff --git a/hb_client/.env.development b/hb_client/.env.development index 003a43c..ef83e12 100644 --- a/hb_client/.env.development +++ b/hb_client/.env.development @@ -2,8 +2,8 @@ ENV = 'development' # base api -#VUE_APP_BASE_API = 'http://127.0.0.1:8000/api' -VUE_APP_BASE_API = 'http://47.95.0.242:2222/api' +VUE_APP_BASE_API = 'http://127.0.0.1:8000/api' +#VUE_APP_BASE_API = 'http://47.95.0.242:2222/api' # vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable, diff --git a/hb_client/src/api/mtm.js b/hb_client/src/api/mtm.js index 940a086..07d16f7 100644 --- a/hb_client/src/api/mtm.js +++ b/hb_client/src/api/mtm.js @@ -226,6 +226,36 @@ export function deleteOutputmaterial(id, data) { data }) } +//其他材料 +export function getOthermaterialList(query) { + return request({ + url: '/mtm/othermaterial/', + method: 'get', + params: query + }) +} +export function createOthermaterial(data) { + return request({ + url: '/mtm/othermaterial/', + method: 'post', + data + }) +} +export function updateOthermaterial(id, data) { + return request({ + url: `/mtm/othermaterial/${id}/`, + method: 'put', + data + }) +} +export function deleteOthermaterial(id, data) { + return request({ + url: `/mtm/othermaterial/${id}/`, + method: 'delete', + data + }) +} + //子工序 export function getUsedstepList(query) { diff --git a/hb_client/src/views/em/equipment.vue b/hb_client/src/views/em/equipment.vue index 2b89c67..740b0d3 100644 --- a/hb_client/src/views/em/equipment.vue +++ b/hb_client/src/views/em/equipment.vue @@ -79,7 +79,7 @@ - + @@ -208,8 +208,13 @@ - - + + diff --git a/hb_client/src/views/mtm/productprocess.vue b/hb_client/src/views/mtm/productprocess.vue index c2b2eac..a8e421e 100644 --- a/hb_client/src/views/mtm/productprocess.vue +++ b/hb_client/src/views/mtm/productprocess.vue @@ -232,13 +232,16 @@ - + + :key="item.id" + :label="item.name" + :value="item.id"> + {{ item.name }} + {{ item.specification }} + @@ -330,12 +333,14 @@ - + + :key="item.id" + :label="item.name" + :value="item.id"> + {{ item.name }} + {{ item.specification }} @@ -359,6 +364,103 @@ + + + 新增 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ item.name }} + {{ item.specification }} + + + + + + + + + +
+ 取消 + 确认 +
+
+
+ 新增 @@ -532,7 +634,8 @@ import { getMaterialList,getMaterial,getInputmaterialList,createInputmaterial,updateInputmaterial ,deleteInputmaterial,getOutputmaterialList,createOutputmaterial,updateOutputmaterial,deleteOutputmaterial, getUsedstepList,createUsedstep,deleteUsedstep,getStepList,gettechdocList,createtechdoc,updatetechdoc,deletetechdoc -,getsubproducationList,createsubproducation,updatesubproducation,deletesubproducation,getProcessList } from "@/api/mtm"; +,getsubproducationList,createsubproducation,updatesubproducation,deletesubproducation,getProcessList , +getOthermaterialList,createOthermaterial,deleteOthermaterial} from "@/api/mtm"; import { quillEditor } from 'vue-quill-editor' import 'quill/dist/quill.core.css' import 'quill/dist/quill.snow.css' @@ -548,6 +651,7 @@ const defaultinputmaterial = { const defaultoutputmaterial = { }; +const defaultother = {}; const defaultusedstep = { }; @@ -569,11 +673,13 @@ export default { editorOption: {} , processOptions:[], is_main:false, + othermaterial:defaultother, techdoc: defaulttechdoc, subproducation:defaultsubproducation, inputmaterial: defaultinputmaterial, techdoctableData:"", outputtableData:"", + othertableData:"", outputmaterial: defaultoutputmaterial, usedsteptableData:"", usedstep: defaultusedstep, @@ -601,6 +707,9 @@ export default { listQueryusedstep: { page: 0, }, + listQueryother: { + page: 0, + }, listQuerytechdoc:{ page: 0, }, @@ -619,6 +728,8 @@ export default { dialogVisibleusedstep:false, dialogTypet: "new", dialogVisiblet:false, + dialogVisibleother:false, + dialogTypeother: "new", listLoading: true, }; @@ -648,7 +759,7 @@ export default { this.listLoading = true; getMaterialList({pageoff:true}).then((response) => { if (response.data) { - this.materialoptions = genTree(response.data); + this.materialoptions = response.data; } this.listLoading = false; }); @@ -680,29 +791,16 @@ export default { handlespChange(row){ this.subproduction = row.id; this.processes = row.process; - this.getmaterialList();//物料列表 + this.getInputmaterialLists();//输入物料 this.getOutputmaterialLists();//输出物料 + this.getOthermaterialLists();//辅助工装 this.getstepList();//子工序 this. getUsedstepLists();// this.gettechdocLists();//技术文件 }, - //工艺点击信息 - - stepclick(id) - { - this.process = id; - // alert(this.process) - this.getmaterialList();//物料列表 - this.getInputmaterialLists();//输入物料 - - this.getOutputmaterialLists();//输出物料 - this.getstepList();//子工序 - this. getUsedstepLists();// - this.gettechdocLists();//技术文件 - - }, + //产品分解 getsubproducationList(){ @@ -798,6 +896,7 @@ export default { this.$nextTick(() => { this.$refs["Form"].clearValidate(); }); + this.getmaterialList();//物料列表 }, handleinputEdit(scope) { this.inputmaterial = Object.assign({}, scope.row); // copy obj @@ -878,6 +977,7 @@ export default { this.$nextTick(() => { this.$refs["Forms"].clearValidate(); }); + this.getmaterialList();//物料列表 }, handleoutputEdit(scope) { this.outputmaterial = Object.assign({}, scope.row); // copy obj @@ -931,6 +1031,84 @@ export default { } }); }, + + //输入其他物料列表 + + getOthermaterialLists(){ + + this.listQueryother.subproduction=this.subproduction; + getOthermaterialList(this.listQueryother).then((response) => { + if (response.data) { + + this.othertableData = response.data;//工装列表 + + } + }) + }, + //输入其他物料 + handleotherCreate() { + this.othermaterial = Object.assign({}, defaultother); + this.dialogTypeother = "new"; + this.dialogVisibleother = true; + this.$nextTick(() => { + this.$refs["Formother"].clearValidate(); + }); + this.getmaterialList();//物料列表 + }, + handleotherEdit(scope) { + this.othermaterial = Object.assign({}, scope.row); // copy obj + this.dialogTypeother = "edit"; + this.dialogVisibleother = true; + this.$nextTick(() => { + this.$refs["Formother"].clearValidate(); + }); + }, + handleotherDelete(scope) { + this.$confirm("确认删除?", "警告", { + confirmButtonText: "确认", + cancelButtonText: "取消", + type: "error", + }) + .then(async () => { + await deleteOthermaterial(scope.row.id); + this.getOthermaterialLists() + this.$message.success("成功"); + }) + .catch((err) => { + console.error(err); + }); + }, + async otherconfirm(form) { + this.$refs[form].validate((valid) => { + if (valid) { + const isEdit = this.dialogTypeother === "edit"; + if (isEdit) { + this.othermaterial.subproduction=this.subproduction; + updateOthermaterial(this.othermaterial.id, this.othermaterial).then((res) => { + if (res.code >= 200) { + this.getOthermaterialLists() + this.dialogVisibleother = false; + this.$message.success("成功"); + } + }); + } else { + this.othermaterial.subproduction=this.subproduction; + createOthermaterial(this.othermaterial).then((res) => { + if (res.code >= 200) { + this.getOthermaterialLists() + this.dialogVisibleother = false; + this.$message.success("成功"); + } + }); + } + } else { + return false; + } + }); + }, + + + //子工序列表 getUsedstepLists(){ diff --git a/hb_server/apps/inm/migrations/0008_auto_20211102_0935.py b/hb_server/apps/inm/migrations/0008_auto_20211102_0935.py new file mode 100644 index 0000000..2349543 --- /dev/null +++ b/hb_server/apps/inm/migrations/0008_auto_20211102_0935.py @@ -0,0 +1,25 @@ +# Generated by Django 3.2.6 on 2021-11-02 01:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wpm', '0002_auto_20211029_1336'), + ('inm', '0007_auto_20211028_1331'), + ] + + operations = [ + migrations.AddField( + model_name='iproduct', + name='wproduct', + field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='关联的动态产品'), + ), + migrations.AlterField( + model_name='materialbatch', + name='batch', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='批次号'), + ), + ] diff --git a/hb_server/apps/inm/migrations/0009_auto_20211102_1113.py b/hb_server/apps/inm/migrations/0009_auto_20211102_1113.py new file mode 100644 index 0000000..cb6e575 --- /dev/null +++ b/hb_server/apps/inm/migrations/0009_auto_20211102_1113.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.6 on 2021-11-02 03:13 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inm', '0008_auto_20211102_0935'), + ] + + operations = [ + migrations.AddField( + model_name='fifo', + name='is_audited', + field=models.BooleanField(default=False, verbose_name='是否审核'), + ), + migrations.AddField( + model_name='fifodetail', + name='is_tested', + field=models.BooleanField(default=False, verbose_name='是否检测'), + ), + ] diff --git a/hb_server/apps/inm/models.py b/hb_server/apps/inm/models.py index 9a2ac61..eefa002 100644 --- a/hb_server/apps/inm/models.py +++ b/hb_server/apps/inm/models.py @@ -41,7 +41,7 @@ class MaterialBatch(BaseModel): material = models.ForeignKey(Material, on_delete=models.CASCADE, verbose_name='物料信息') warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库') count = models.IntegerField('存量', default=0) - batch = models.CharField('批次号', max_length=100, null=True, blank=True, unique=True) + batch = models.CharField('批次号', max_length=100, null=True, blank=True) expiration_date = models.DateField('有效期', null=True, blank=True) class Meta: verbose_name = '库存表' @@ -60,6 +60,7 @@ class FIFO(CommonAModel): (4, '生产入库') ) type = models.IntegerField('出入库类型', default=1) + is_audited = models.BooleanField('是否审核', default=False) warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='仓库') operator = models.ForeignKey(User, verbose_name='操作人', on_delete=models.CASCADE) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.DO_NOTHING, null=True, blank=True) @@ -71,6 +72,8 @@ class FIFODetail(BaseModel): """ 出入库详细记录 """ + is_tested = models.BooleanField('是否已检测', default=False) + is_testok = models.BooleanField('是否检测合格', default=False) material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE) count = models.IntegerField('数量', default=0) batch = models.CharField('批次号', max_length=100, null=True, blank=True) diff --git a/hb_server/apps/inm/serializers.py b/hb_server/apps/inm/serializers.py index 191a2dd..0087fae 100644 --- a/hb_server/apps/inm/serializers.py +++ b/hb_server/apps/inm/serializers.py @@ -83,9 +83,10 @@ class FIFOInPurSerializer(serializers.ModelSerializer): for i in details: # 校验批次 try: - obj = MaterialBatch.objects.get(batch=i['batch']) - if obj.warehouse != validated_data['warehouse']: - raise serializers.ValidationError('批次号{}在其他仓库已存在'.format(i['batch'])) + if i['batch']: + obj = MaterialBatch.objects.get(batch=i['batch'], material=i['material']) + if obj.warehouse != validated_data['warehouse']: + raise serializers.ValidationError('批次号{}在其他仓库已存在'.format(i['batch'])) except: pass diff --git a/hb_server/apps/inm/signals.py b/hb_server/apps/inm/signals.py index 339e5e9..800621a 100644 --- a/hb_server/apps/inm/signals.py +++ b/hb_server/apps/inm/signals.py @@ -1,35 +1,38 @@ from django.db.models.signals import post_save from django.dispatch import receiver -from apps.inm.models import FIFODetail, Inventory, MaterialBatch +from apps.inm.models import Inventory, MaterialBatch, FIFO, FIFODetail -@receiver(post_save, sender=FIFODetail) -def update_by_fifodetail(sender, instance, created, **kwargs): - if created: - fifo = instance.fifo - material = instance.material - warehouse = fifo.warehouse - if fifo.type in [3]: # 采购入库 - # 更新相关表 +def update_inm(instance:FIFO, type:int): + """ + 更新库存(正反) + """ + warehouse = instance.warehouse + if instance.type in [3]: # 采购入库 + # 更新相关表 + for i in FIFODetail.objects.filter(fifo=instance): + material = i.material o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \ defaults={'material':material, 'warehouse':warehouse, 'count':0}) - o1.count = o1.count + instance.count + o1.count = o1.count + i.count o1.save() - o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=instance.batch,\ - defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':instance.batch}) - o2.count = o2.count + instance.count + o2, _ = MaterialBatch.objects.get_or_create(material=material, warehouse=warehouse, batch=i.batch,\ + defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':i.batch}) + o2.count = o2.count + i.count o2.save() - material.count = material.count + instance.count + material.count = material.count + i.count material.save() - elif fifo.type in [1]: # 生产领料 - # 更新相关表 + elif instance.type in [1]: # 生产领料 + # 更新相关表 + for i in FIFODetail.objects.filter(fifo=instance): + material = i.material o1 = Inventory.objects.get(material=material, warehouse=warehouse) - o1.count = o1.count - instance.count + o1.count = o1.count - i.count o1.save() - o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=instance.batch) - o2.count = o2.count - instance.count + o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=i.batch) + o2.count = o2.count - i.count o2.save() - material.count = material.count - instance.count + material.count = material.count - i.count material.save() diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index 927e0ee..0fd15d8 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -1,11 +1,13 @@ from django.shortcuts import render from rest_framework import serializers +from rest_framework.exceptions import APIException from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.viewsets import GenericViewSet, ModelViewSet from apps.inm.filters import MbFilterSet from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse,Inventory from apps.inm.serializers import FIFODetailSerializer, FIFOInPurSerializer, FIFOListSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer +from apps.inm.signals import update_inm from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action from rest_framework.response import Response @@ -72,7 +74,7 @@ class FIFODetailViewSet(ListModelMixin, GenericViewSet): search_fields = [] ordering_fields = ['create_time'] ordering = ['-create_time'] - + class FIFOViewSet(ListModelMixin, GenericViewSet): """ 出入库记录 @@ -80,7 +82,10 @@ class FIFOViewSet(ListModelMixin, GenericViewSet): perms_map = {'*': '*'} queryset = FIFO.objects.select_related('warehouse', 'operator') serializer_class = FIFOListSerializer - filterset_fields = ['warehouse', 'type'] + filterset_fields = '__all__' + ordering_fields = '__all__' + search_fields = ['warehouse__name', 'warehouse__number'] + ordering = ['-pk'] def get_serializer_class(self): if self.action == 'list': @@ -96,4 +101,18 @@ class FIFOViewSet(ListModelMixin, GenericViewSet): serializer.is_valid(raise_exception=True) serializer.save(create_by=request.user) return Response() + + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) + def audit(self, request, pk=None): + """ + 审核通过 + """ + obj = self.get_object() + for i in FIFODetail.objects.filter(fifo=obj): + if not i.is_testok: + raise APIException('未检验通过, 不可审核') + obj.is_audited = True + obj.save() + update_inm(obj) # 更新库存 + return Response() \ No newline at end of file diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index 2a23ec3..a86784b 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -88,6 +88,7 @@ class RecordForm(CommonAModel): type = models.IntegerField('表格类型', choices=type_choices, default=1) step = models.ForeignKey(Step, verbose_name='关联子工序', on_delete=models.CASCADE, null=True, blank=True) material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE, null=True, blank=True) + class Meta: verbose_name = '记录表格' verbose_name_plural = verbose_name @@ -130,7 +131,7 @@ class RecordFormField(CommonAModel): field_choice = models.JSONField('radio、checkbox、select的选项', default=dict, blank=True, null=True, help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号') sort = models.IntegerField('排序号', default=1) - need_judge = models.BooleanField('需要判定', default=False) + need_judge = models.BooleanField('需要判定项目', default=False) high_limit = models.FloatField('上限值', null=True, blank=True) high_rule = models.IntegerField('上限规则', choices=high_rule_choices, null=True, blank=True) low_limit = models.FloatField('下限值', null=True, blank=True) diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py index f0e6deb..21b549b 100644 --- a/hb_server/apps/mtm/serializers.py +++ b/hb_server/apps/mtm/serializers.py @@ -151,6 +151,11 @@ class UsedStepListSerializer(serializers.ModelSerializer): queryset = queryset.select_related('step') return queryset +class RecordFormSimpleSerializer(serializers.ModelSerializer): + + class Meta: + model = RecordForm + fields = ['id', 'name'] class RecordFormSerializer(serializers.ModelSerializer): step_ = StepSimpleSerializer(source='step', read_only=True) material_ = MaterialSimpleSerializer(source='material', read_only=True) @@ -182,6 +187,26 @@ class RecordFormFieldSerializer(serializers.ModelSerializer): model = RecordFormField fields = '__all__' +class RecordFormDetailSerializer(serializers.ModelSerializer): + step_ = StepSimpleSerializer(source='step', read_only=True) + material_ = MaterialSimpleSerializer(source='material', read_only=True) + form_fields = serializers.SerializerMethodField() + + class Meta: + model = RecordForm + fields = '__all__' + + @staticmethod + def setup_eager_loading(queryset): + """ Perform necessary eager loading of data. """ + queryset = queryset.select_related('step', 'material') + return queryset + + def get_form_fields(self, obj): + serializer = RecordFormFieldSerializer(instance=RecordFormField.objects.filter(form=obj, is_deleted=False), many=True) + return serializer.data + + class RecordFormFieldCreateSerializer(serializers.ModelSerializer): class Meta: model = RecordFormField diff --git a/hb_server/apps/mtm/views.py b/hb_server/apps/mtm/views.py index 64e62f2..3dd563c 100644 --- a/hb_server/apps/mtm/views.py +++ b/hb_server/apps/mtm/views.py @@ -3,7 +3,7 @@ from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin from apps.mtm.models import Material, Process, RecordForm, RecordFormField, Step, SubplanMaterial, TechDoc, UsedStep, SubProduction -from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, SubplanMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer +from apps.mtm.serializers import InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OtherMaterialSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormDetailSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, SubProductionSerializer, SubplanMaterialListSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer, UsedStepUpdateSerializer from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action from rest_framework.response import Response @@ -159,6 +159,8 @@ class RecordFormViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet return RecordFormCreateSerializer elif self.action == 'update': return RecordFormUpdateSerializer + elif self.action == 'retrieve': + return RecordFormDetailSerializer return RecordFormSerializer @action(methods=['get'], detail=True, perms_map={'get':'*'}, pagination_class=None, serializer_class=RecordFormFieldSerializer) @@ -170,6 +172,8 @@ class RecordFormViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet serializer = self.serializer_class(instance=RecordFormField.objects.filter(form=instance, is_deleted=False), many=True) return Response(serializer.data) + + class RecordFormFieldViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet): """ diff --git a/hb_server/apps/pum/models.py b/hb_server/apps/pum/models.py index a705f8a..bf5d5a7 100644 --- a/hb_server/apps/pum/models.py +++ b/hb_server/apps/pum/models.py @@ -18,7 +18,6 @@ class Vendor(CommonAModel): contact_phone = models.CharField('联系电话', max_length=11, unique=True) address = models.CharField('地址', max_length=200, null=True, blank=True) description = models.CharField('描述', max_length=200, blank=True, null=True) - material = models.CharField('供应的物料', max_length=200, blank=True, null=True) class Meta: verbose_name = '供应商信息' verbose_name_plural = verbose_name diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py index 4e667cd..062f5c9 100644 --- a/hb_server/apps/qm/models.py +++ b/hb_server/apps/qm/models.py @@ -38,4 +38,15 @@ class AnalysisItem(CommonAModel): rules =models.JSONField('判定规则', default=list) class Meta: - verbose_name = '检验分析项' \ No newline at end of file + verbose_name = '检验分析项' + +class TestRecord(CommonAModel): + """ + 检验记录 + """ + + form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE) + record_data = models.JSONField('记录数据', default=dict, blank=True) + is_testok = models.BooleanField('是否合格', default=True) + fifo_detail = models.ForeignKey('inm.fifodetail', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True) + \ No newline at end of file diff --git a/hb_server/apps/qm/serializers.py b/hb_server/apps/qm/serializers.py index a656332..51d5cb7 100644 --- a/hb_server/apps/qm/serializers.py +++ b/hb_server/apps/qm/serializers.py @@ -1,6 +1,8 @@ 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 .models import Standard, TestItem +from .models import Standard, TestItem, TestRecord class StandardCreateUpdateSerializer(serializers.ModelSerializer): class Meta: @@ -31,3 +33,41 @@ class TestItemSerializer(serializers.ModelSerializer): class AnalysisItemSerializer(serializers.ModelSerializer): pass + + +class TestRecordCreateSerializer(serializers.ModelSerializer): + class Meta: + model = TestRecord + fields = ['form', 'record_data', 'is_testok', 'fifo_detail'] + + def create(self, validated_data): + if 'is_testok' not in validated_data: + raise serializers.ValidationError('未填写检测结论') + return super().create(validated_data) + +class TestRecordListSerializer(serializers.ModelSerializer): + class Meta: + model = TestRecord + fields = '__all__' + + +class TestRecordDetailSerializer(serializers.ModelSerializer): + form_ = RecordFormSimpleSerializer(source='form', read_only=True) + record_data_ = serializers.SerializerMethodField() + class Meta: + model = TestRecord + fields = '__all__' + + @staticmethod + def setup_eager_loading(queryset): + queryset = queryset.select_related('form','fifo_detail') + 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 diff --git a/hb_server/apps/qm/urls.py b/hb_server/apps/qm/urls.py index 070d39b..913ca82 100644 --- a/hb_server/apps/qm/urls.py +++ b/hb_server/apps/qm/urls.py @@ -1,4 +1,4 @@ -from apps.qm.views import StandardViewSet, TestItemViewSet +from apps.qm.views import StandardViewSet, TestItemViewSet, TestRecordViewSet from django.db.models import base from rest_framework import urlpatterns from django.urls import path, include @@ -7,6 +7,7 @@ from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register('standard', StandardViewSet, basename='standard') router.register('testitem', TestItemViewSet, basename='testitem') +router.register('testrecord', TestRecordViewSet, basename='testrecord') urlpatterns = [ path('', include(router.urls)), ] diff --git a/hb_server/apps/qm/views.py b/hb_server/apps/qm/views.py index da02e97..41133f5 100644 --- a/hb_server/apps/qm/views.py +++ b/hb_server/apps/qm/views.py @@ -1,5 +1,5 @@ -from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer -from apps.qm.models import Standard, TestItem +from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer, TestRecordCreateSerializer, TestRecordDetailSerializer, TestRecordListSerializer +from apps.qm.models import Standard, TestItem, TestRecord from django.shortcuts import render from rest_framework.viewsets import ModelViewSet from apps.system.mixins import CreateUpdateModelAMixin @@ -37,3 +37,29 @@ class TestItemViewSet(CreateUpdateModelAMixin, ModelViewSet): if self.action in ['create', 'update']: return TestItemCreateUpdateSerializer return TestItemSerializer + +class TestRecordViewSet(ModelViewSet): + """ + 检测记录 + """ + perms_map = {'*': '*'} + queryset = TestRecord.objects.select_related('fifo_detail', 'form').all() + serializer_class = TestRecordListSerializer + ordering = ['-id'] + + def get_serializer_class(self): + if self.action == 'create': + return TestRecordCreateSerializer + elif self.action == 'list': + return TestRecordListSerializer + elif self.action == 'retrieve': + return TestRecordDetailSerializer + return super().get_serializer_class() + + def perform_create(self, serializer): + obj = serializer.save(create_by = self.request.user) + # 如果检测合格 + if obj.fifo_detail: + obj.fifo_detail.is_testok = True if obj.is_testok else False + obj.fifo_detail.is_tested = True + obj.fifo_detail.save() \ No newline at end of file diff --git a/hb_server/apps/wpm/migrations/0003_auto_20211102_0935.py b/hb_server/apps/wpm/migrations/0003_auto_20211102_0935.py new file mode 100644 index 0000000..fcf3bed --- /dev/null +++ b/hb_server/apps/wpm/migrations/0003_auto_20211102_0935.py @@ -0,0 +1,26 @@ +# Generated by Django 3.2.6 on 2021-11-02 01:35 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pm', '0009_auto_20211029_1017'), + ('wpm', '0002_auto_20211029_1336'), + ] + + operations = [ + migrations.AddField( + model_name='wproduct', + name='production_plan', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='pm.productionplan', verbose_name='关联主生产计划'), + preserve_default=False, + ), + migrations.AlterField( + model_name='wproduct', + name='subproduction_plan', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='当前子生产计划'), + ), + ] diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 7b74167..e9c9bb3 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -1,6 +1,7 @@ from rest_framework import serializers from rest_framework.serializers import ModelSerializer from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse +from apps.inm.signals import update_inm from apps.mtm.models import Material from apps.mtm.serializers import MaterialSimpleSerializer @@ -37,7 +38,7 @@ class PickSerializer(serializers.Serializer): validated_data['operator'] = operator validated_data['type'] = 1 validated_data['inout_date'] = timezone.now() - fifo = FIFO.objects.create(validated_data) + fifo = FIFO.objects.create(**validated_data) for i in picks: # 更新出库详情 i['fifo'] = fifo @@ -53,12 +54,16 @@ class PickSerializer(serializers.Serializer): }) wm.count = wm.count + i['pick_count'] wm.save() - # 更新子计划进度 + # 更新子计划物料情况 spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1) spp.count_real = spp.count_real + i['pick_count'] spp.save() sp.is_picked=True sp.save() + # 更新库存 + fifo.is_audited = True + fifo.save() + update_inm(fifo) return fifo class WMaterialListSerializer(serializers.ModelSerializer): diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 0630101..8a3dc4e 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -31,4 +31,10 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet): serializer= PickSerializer(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) serializer.save() - return Response() \ No newline at end of file + return Response() + +class DoFormInit(CreateAPIView): + """ + 生产操作表单创建 + """ + perms_map={'*':'*'} \ No newline at end of file diff --git a/hb_server/utils/viewset.py b/hb_server/utils/viewset.py new file mode 100644 index 0000000..e4c4c84 --- /dev/null +++ b/hb_server/utils/viewset.py @@ -0,0 +1,6 @@ +from rest_framework.viewsets import GenericViewSet + +class MyGenericViewSet(GenericViewSet): + filterset_fields = '__all__' + ordering_fields = '__all__' + ordering = ['-pk'] \ No newline at end of file