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()