From 74c787960edb670ac12388b5aa86de4e0d28927b Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 29 Oct 2021 15:06:10 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E5=87=BA=E5=85=A5=E5=BA=93=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E4=B8=AD=E9=97=B4=E8=A1=A8bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/signals.py | 12 ++++++- hb_server/apps/pm/serializers.py | 3 ++ hb_server/apps/pm/views.py | 12 +++++-- hb_server/apps/wpm/migrations/0001_initial.py | 1 - .../wpm/migrations/0002_auto_20211029_1336.py | 28 +++++++++++++++++ hb_server/apps/wpm/models.py | 5 +-- hb_server/apps/wpm/serializers.py | 31 +++++++++++++++++-- hb_server/apps/wpm/urls.py | 4 ++- hb_server/apps/wpm/views.py | 18 +++++++++-- hb_server/server/urls.py | 2 ++ 10 files changed, 105 insertions(+), 11 deletions(-) create mode 100644 hb_server/apps/wpm/migrations/0002_auto_20211029_1336.py diff --git a/hb_server/apps/inm/signals.py b/hb_server/apps/inm/signals.py index e638fd1..339e5e9 100644 --- a/hb_server/apps/inm/signals.py +++ b/hb_server/apps/inm/signals.py @@ -20,6 +20,16 @@ def update_by_fifodetail(sender, instance, created, **kwargs): defaults={'material':material, 'warehouse':warehouse, 'count':0, 'batch':instance.batch}) o2.count = o2.count + instance.count o2.save() - material.count = material.count + 1 + material.count = material.count + instance.count + material.save() + elif fifo.type in [1]: # 生产领料 + # 更新相关表 + o1 = Inventory.objects.get(material=material, warehouse=warehouse) + o1.count = o1.count - instance.count + o1.save() + o2 = MaterialBatch.objects.get(material=material, warehouse=warehouse, batch=instance.batch) + o2.count = o2.count - instance.count + o2.save() + material.count = material.count - instance.count material.save() diff --git a/hb_server/apps/pm/serializers.py b/hb_server/apps/pm/serializers.py index 51821b9..8b170a5 100644 --- a/hb_server/apps/pm/serializers.py +++ b/hb_server/apps/pm/serializers.py @@ -47,3 +47,6 @@ class SubProductionProgressSerializer(serializers.ModelSerializer): class PickNeedSerializer(serializers.Serializer): warehouse = serializers.IntegerField(label="仓库ID") + +class PlanDestorySerializer(serializers.Serializer): + ids = serializers.ListField(child=serializers.IntegerField(), label='主计划ID列表') diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py index 6e3f340..429115e 100644 --- a/hb_server/apps/pm/views.py +++ b/hb_server/apps/pm/views.py @@ -7,7 +7,7 @@ from apps.inm.models import MaterialBatch from apps.inm.serializers import MaterialBatchSerializer from apps.mtm.models import InputMaterial, OutputMaterial, Step, SubProduction, UsedStep from apps.system.mixins import CreateUpdateModelAMixin -from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer +from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin from apps.pm.models import ProductionPlan, SubProductionProgress, SubProductionPlan from rest_framework.viewsets import GenericViewSet, ModelViewSet @@ -63,6 +63,14 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel updateOrderPlanedCount(instance.order) return Response() + @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PlanDestorySerializer) + def destory(self, request, pk=None): + """ + 批量物理删除 + """ + ProductionPlan.objects.filter(id__in=request.data.get('ids', [])).delete(soft=False) + return Response() + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=GenSubPlanSerializer) def gen_subplan(self, request, pk=None): """ @@ -95,7 +103,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo queryset = SubProductionPlan.objects.select_related('process', 'workshop') search_fields = [] serializer_class = SubProductionPlanListSerializer - filterset_fields = ['production_plan'] + filterset_fields = ['production_plan', 'process', 'state'] ordering_fields = ['process__number'] ordering = ['process__number'] diff --git a/hb_server/apps/wpm/migrations/0001_initial.py b/hb_server/apps/wpm/migrations/0001_initial.py index 596bbed..75511e7 100644 --- a/hb_server/apps/wpm/migrations/0001_initial.py +++ b/hb_server/apps/wpm/migrations/0001_initial.py @@ -77,7 +77,6 @@ class Migration(migrations.Migration): ('batch', models.CharField(blank=True, max_length=100, null=True, verbose_name='批次号')), ('count', models.IntegerField(default=0, verbose_name='当前数量')), ('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='关联物料')), - ('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子计划')), ], options={ 'abstract': False, diff --git a/hb_server/apps/wpm/migrations/0002_auto_20211029_1336.py b/hb_server/apps/wpm/migrations/0002_auto_20211029_1336.py new file mode 100644 index 0000000..1787907 --- /dev/null +++ b/hb_server/apps/wpm/migrations/0002_auto_20211029_1336.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.6 on 2021-10-29 05:36 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('system', '0003_auto_20210812_0909'), + ('mtm', '0025_outputmaterial_is_main'), + ('wpm', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='wmaterial', + name='process', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='mtm.process', verbose_name='关联大工序'), + preserve_default=False, + ), + migrations.AddField( + model_name='wmaterial', + name='workshop', + field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='system.organization', verbose_name='生产车间'), + preserve_default=False, + ), + ] diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index af2de44..b68579b 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -6,13 +6,14 @@ from apps.pm.models import SubProductionPlan from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File from utils.model import SoftModel, BaseModel from simple_history.models import HistoricalRecords -from apps.mtm.models import Material, Step, RecordForm +from apps.mtm.models import Material, Process, Step, RecordForm class WMaterial(BaseModel): """ 车间生产物料 """ - subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子计划', on_delete=models.CASCADE) + workshop = models.ForeignKey(Organization, verbose_name='生产车间', on_delete=models.CASCADE) + process = models.ForeignKey(Process, verbose_name='关联大工序', on_delete=models.CASCADE) material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE) batch = models.CharField('批次号', max_length=100, null=True, blank=True) count = models.IntegerField('当前数量', default=0) diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 39a4542..8eb76bb 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -1,10 +1,37 @@ from rest_framework import serializers from rest_framework.serializers import ModelSerializer +from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse +from apps.mtm.models import Material + +from apps.pm.models import SubProductionPlan +from django.utils import timezone class PickDetailSerializer(serializers.Serializer): - material = serializers.IntegerField(label='物料ID') + material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID") batch = serializers.CharField(label='物料批次') pick_count = serializers.IntegerField(label="领料数量") class PickSerializer(serializers.Serializer): - warehouse = serializers.IntegerField(label="仓库ID") \ No newline at end of file + subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID") + warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") + picks = PickDetailSerializer(many=True) + + def create(self, validated_data): + picks = validated_data.pop('picks') + for i in picks: + try: + instance = MaterialBatch.objects.get(material=i['material'], batch=i['batch']) + if instance.count < i['pick_count']: + raise serializers.ValidationError('物料不足') + except: + raise serializers.ValidationError('物料不存在') + operator = self.context['request'].user + validated_data['create_by'] = operator + validated_data['operator'] = operator + validated_data['type'] = 1 + validated_data['inout_date'] = timezone.now() + fifo = FIFO.objects.create(validated_data) + for i in picks: + i['fifo'] = fifo + FIFODetail.objects.create(**i) + return fifo \ No newline at end of file diff --git a/hb_server/apps/wpm/urls.py b/hb_server/apps/wpm/urls.py index a0e8919..d4685ec 100644 --- a/hb_server/apps/wpm/urls.py +++ b/hb_server/apps/wpm/urls.py @@ -3,8 +3,10 @@ from rest_framework import urlpatterns from django.urls import path, include from rest_framework.routers import DefaultRouter -router = DefaultRouter() +from apps.wpm.views import WMaterialViewSet +router = DefaultRouter() +router.register('wmaterial', WMaterialViewSet, basename='wmaterial') urlpatterns = [ path('', include(router.urls)), ] diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index b9c6679..91e5122 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -1,12 +1,26 @@ from django.shortcuts import render from rest_framework.generics import CreateAPIView, GenericAPIView +from rest_framework.utils.field_mapping import get_relation_kwargs from rest_framework.viewsets import GenericViewSet, ModelViewSet +from apps.pm.serializers import SubProductionPlanUpdateSerializer from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin +from rest_framework.decorators import action +from apps.wpm.serializers import PickSerializer +from rest_framework.response import Response # Create your views here. -class WpmPickView(CreateUpdateModelAMixin, CreateAPIView): +class WMaterialViewSet(CreateUpdateModelAMixin, GenericViewSet): """ 领料 """ - pass \ No newline at end of file + perms_map={'*':'*'} + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=PickSerializer) + def pick(self, request, pk=None): + """ + 领料 + """ + serializer= PickSerializer(data=request.data, context={'request': request}) + serializer.is_valid(raise_exception=True) + serializer.save() + return Response() \ No newline at end of file diff --git a/hb_server/server/urls.py b/hb_server/server/urls.py index af315af..b5ac030 100644 --- a/hb_server/server/urls.py +++ b/hb_server/server/urls.py @@ -68,6 +68,8 @@ urlpatterns = [ path('api/sam/', include('apps.sam.urls')), path('api/qm/', include('apps.qm.urls')), path('api/pm/', include('apps.pm.urls')), + path('api/wpm/', include('apps.wpm.urls')), + # 工具 path('api/utils/signature/', GenSignature.as_view()), From d832878c5039d07b56b287a4b7eee17077e81665 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 1 Nov 2021 08:57:06 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E9=A2=86=E6=96=99=E9=9C=80=E6=B1=82?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/serializers.py | 11 +++++++++++ hb_server/apps/inm/views.py | 19 ++++++++++--------- hb_server/apps/pm/views.py | 10 ++++++++++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/hb_server/apps/inm/serializers.py b/hb_server/apps/inm/serializers.py index b0945ef..191a2dd 100644 --- a/hb_server/apps/inm/serializers.py +++ b/hb_server/apps/inm/serializers.py @@ -79,6 +79,17 @@ class FIFOInPurSerializer(serializers.ModelSerializer): pass else: raise serializers.ValidationError('没有入库内容') + + for i in details: + # 校验批次 + try: + obj = MaterialBatch.objects.get(batch=i['batch']) + if obj.warehouse != validated_data['warehouse']: + raise serializers.ValidationError('批次号{}在其他仓库已存在'.format(i['batch'])) + except: + pass + + # 创建采购入库 validated_data['type'] = 3 obj = FIFO(**validated_data) obj.save() diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index cae03de..927e0ee 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -50,15 +50,16 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet): ordering_fields = ['create_time'] ordering = ['-create_time'] - # @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=MaterialBatchQuerySerializer) - # def query(self, request, pk=None): - # """ - # 复杂查询 - # """ - # serializer = MaterialBatchQuerySerializer(data=request.data) - # serializer.is_valid(raise_exception=True) - # queryset = self.queryset.filter() - # return Response() + @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=MaterialBatchQuerySerializer) + def query(self, request, pk=None): + """ + 复杂查询 + """ + data = request.data + serializer = MaterialBatchQuerySerializer(data=data) + serializer.is_valid(raise_exception=True) + queryset = self.queryset.filter(warehouse__id=data['warehouse'], material__id__in=data['materials']) + return Response(MaterialBatchSerializer(instance=queryset, many=True).data) class FIFODetailViewSet(ListModelMixin, GenericViewSet): """ diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py index 429115e..b7dfacb 100644 --- a/hb_server/apps/pm/views.py +++ b/hb_server/apps/pm/views.py @@ -148,6 +148,16 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo return Response() raise APIException('计划状态有误') + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) + def pick_need_(self, request, pk=None): + """ + 领料需求清单 + """ + obj = self.get_object() + instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=1) + serializer = SubProductionProgressSerializer(instance=instance, many=True) + return Response(serializer.data) + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=PickNeedSerializer) def pick_need(self, request, pk=None): """ From 996cfe5b5df8d6509533558076592a44cbc43326 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 1 Nov 2021 09:01:17 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E9=A2=86=E6=96=99=E9=9C=80=E6=B1=82?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/pm/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py index b7dfacb..617ba95 100644 --- a/hb_server/apps/pm/views.py +++ b/hb_server/apps/pm/views.py @@ -148,7 +148,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo return Response() raise APIException('计划状态有误') - @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer) + @action(methods=['get'], detail=True, perms_map={'get':'*'}, serializer_class=serializers.Serializer) def pick_need_(self, request, pk=None): """ 领料需求清单 From bad2e501f7e0a469e46a16313e7751438a1e8988 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Mon, 1 Nov 2021 09:37:46 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=89=A9=E6=96=99?= =?UTF-8?q?=E5=8D=95=E4=BD=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/mtm/models.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index 2602113..6597138 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -22,7 +22,10 @@ class Material(CommonAModel): ) unit_choices =( ('块', '块'), - ('套', '套') + ('套', '套'), + ('个', '个'), + ('m2', 'm2'), + ('瓶', '瓶') ) name = models.CharField('物料名称', max_length=100, unique=True) number = models.CharField('编号', max_length=100, unique=True)