From acad79288dae3fcd1daf0289ae75c2520e083d3e Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 16 Nov 2021 16:22:12 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=87=AA=E5=AE=9A?= =?UTF-8?q?=E4=B9=89=E8=A1=A8=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/serializers.py | 8 ++ hb_server/apps/inm/views.py | 18 ++- .../mtm/migrations/0034_auto_20211116_1603.py | 43 +++++++ hb_server/apps/mtm/models.py | 14 ++- hb_server/apps/mtm/serializers.py | 4 +- hb_server/apps/wpm/serializers.py | 2 +- hb_server/apps/wpm/views.py | 114 +++++++++--------- 7 files changed, 136 insertions(+), 67 deletions(-) create mode 100644 hb_server/apps/mtm/migrations/0034_auto_20211116_1603.py diff --git a/hb_server/apps/inm/serializers.py b/hb_server/apps/inm/serializers.py index f398159..7f050fc 100644 --- a/hb_server/apps/inm/serializers.py +++ b/hb_server/apps/inm/serializers.py @@ -37,6 +37,14 @@ class MaterialBatchSerializer(serializers. ModelSerializer): model = MaterialBatch fields = '__all__' +class IProductListSerializer(serializers.ModelSerializer): + material_= MaterialSimpleSerializer(source='material', read_only=True) + warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True) + class Meta: + model = IProduct + fields = '__all__' + + class FIFOListSerializer(serializers.ModelSerializer): auditor_ = UserSimpleSerializer(source='auditor', read_only=True) create_by_ = UserSimpleSerializer(source='create_by', read_only=True) diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index 244118e..c05693e 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -5,8 +5,8 @@ from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveMod from rest_framework.viewsets import GenericViewSet, ModelViewSet from apps.inm.filters import MbFilterSet -from apps.inm.models import FIFO, FIFOItem, MaterialBatch, WareHouse,Inventory -from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer +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.signals import update_inm from apps.qm.models import TestRecordItem from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin @@ -160,4 +160,16 @@ class FIFOViewSet(ListModelMixin, GenericViewSet): obj.save() update_inm(obj) # 更新库存 return Response() - \ No newline at end of file + + +class IProductViewSet(ListModelMixin, GenericViewSet): + """ + 半成品库存表 + """ + perms_map = {'*': '*'} + queryset = IProduct.objects.select_related('material', 'warehouse').all() + serializer_class = IProductListSerializer + filterset_fields = ['material', 'warehouse'] + search_fields = [] + ordering_fields = ['create_time'] + ordering = ['-create_time'] \ No newline at end of file diff --git a/hb_server/apps/mtm/migrations/0034_auto_20211116_1603.py b/hb_server/apps/mtm/migrations/0034_auto_20211116_1603.py new file mode 100644 index 0000000..f20ef44 --- /dev/null +++ b/hb_server/apps/mtm/migrations/0034_auto_20211116_1603.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.6 on 2021-11-16 08:03 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('mtm', '0033_alter_recordformfield_rule_expression'), + ] + + operations = [ + migrations.RemoveField( + model_name='recordformfield', + name='boolean_field_display', + ), + migrations.AddField( + model_name='recordformfield', + name='display_expression', + field=models.TextField(blank=True, null=True, verbose_name='字段展现表达式'), + ), + migrations.AddField( + model_name='recordformfield', + name='help_text', + field=models.TextField(blank=True, null=True, verbose_name='说明'), + ), + migrations.AddField( + model_name='recordformfield', + name='is_hidden', + field=models.BooleanField(default=False, verbose_name='是否隐藏'), + ), + migrations.AddField( + model_name='recordformfield', + name='parent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.recordformfield', verbose_name='父'), + ), + migrations.AlterField( + model_name='recordformfield', + name='field_choice', + field=models.JSONField(blank=True, default=list, help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号', null=True, verbose_name='radio、checkbox、select的选项'), + ), + ] diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py index 050ff6f..6a92190 100644 --- a/hb_server/apps/mtm/models.py +++ b/hb_server/apps/mtm/models.py @@ -144,17 +144,23 @@ class RecordFormField(CommonAModel): field_type = models.CharField('类型', max_length=50, choices=field_type_choices) field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突') field_name = models.CharField('字段名称', max_length=50) - boolean_field_display = models.JSONField('布尔类型显示名', default=dict, blank=True, null=True, - help_text='当为布尔类型时候,可以支持自定义显示形式。{"1":"是","0":"否"}或{"1":"需要","0":"不需要"},注意数字也需要引号') - field_choice = models.JSONField('radio、checkbox、select的选项', default=dict, blank=True, null=True, + field_choice = models.JSONField('radio、checkbox、select的选项', default=list, blank=True, null=True, help_text='radio,checkbox,select,multiselect类型可供选择的选项,格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号') + + help_text = models.TextField('说明', null=True, blank=True) sort = models.IntegerField('排序号', default=1) - 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) low_rule = models.IntegerField('下限规则', choices=low_rule_choices, null=True, blank=True) + + need_judge = models.BooleanField('需要判定项目', default=False) rule_expression = models.TextField('判定表达式', null=True, blank=True) + display_expression = models.TextField('字段展现表达式', null=True, blank=True) + is_hidden = models.BooleanField('是否隐藏', default=False) + parent = models.ForeignKey('self', verbose_name='父', on_delete=models.CASCADE, null=True, blank=True) + class Meta: verbose_name = '记录表格字段' diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py index 0d9b82f..b07ccb7 100644 --- a/hb_server/apps/mtm/serializers.py +++ b/hb_server/apps/mtm/serializers.py @@ -215,7 +215,7 @@ class RecordFormDetailSerializer(serializers.ModelSerializer): class RecordFormFieldCreateSerializer(serializers.ModelSerializer): class Meta: model = RecordFormField - fields = ['form', 'field_type', 'field_key', 'field_name', 'boolean_field_display', 'field_choice', 'sort', 'need_judge', 'high_limit', 'high_rule', 'low_limit', 'low_rule', 'rule_expression'] + fields = '__all__' def validate(self, data): if RecordFormField.objects.filter(field_key=data['field_key'], form=data['form'], is_deleted=False).exists(): @@ -225,7 +225,7 @@ class RecordFormFieldCreateSerializer(serializers.ModelSerializer): class RecordFormFieldUpdateSerializer(serializers.ModelSerializer): class Meta: model = RecordFormField - fields = ['field_type', 'field_name', 'boolean_field_display', 'field_choice', 'sort', 'need_judge', 'high_limit', 'high_rule', 'low_limit', 'low_rule', 'rule_expression'] + exclude = ['field_key'] class RecordFormFieldSimpleSerializer(serializers.ModelSerializer): class Meta: diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index b9c4474..5c9a3e0 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -183,7 +183,7 @@ class WpmTestRecordItemCreateSerializer(serializers.ModelSerializer): class WpmTestRecordCreateSerializer(serializers.ModelSerializer): record_data = WpmTestRecordItemCreateSerializer(many=True) wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True) - is_testok = serializers.BooleanField() + is_testok = serializers.BooleanField(required=False) class Meta: model = TestRecord fields = ['form', 'record_data', 'is_testok', 'wproduct'] diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 3f61a0d..a1875a3 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -116,63 +116,6 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet): serializer.save() return Response() - @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer) - @transaction.atomic - def putin(self, request, pk=None): - """ - 半成品入库 - """ - serializer= WproductPutInSerializer(data=request.data) - serializer.is_valid(raise_exception=True) - vdata = serializer.data - wproduct = self.get_object() - if wproduct.act_state != WProduct.WPR_ACT_STATE_OK: - raise exceptions.APIException('半成品不可入库') - material = wproduct.m_state - batch = wproduct.production_plan.number - # 创建入库记录 - remark = vdata.get('remark', '') - fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN, - is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark) - # 创建入库明细 - fifoitem = FIFOItem() - fifoitem.is_tested = True - fifoitem.is_testok = True - fifoitem.warehouse = vdata['warehouse'] - fifoitem.material = material - fifoitem.count = 1 # 单个半成品入库 - fifoitem.batch = batch - fifoitem.fifo = fifo - fifoitem.subproduction_plan = wproduct.subproduction_plan - fifoitem.save() - # 创建入库明细半成品 - ips = [] - for i in [wproduct]: - ip = {} - ip['fifoitem'] = fifoitem - ip['wproduct'] = i - ip['number'] = i.number - ip['material'] = material - ips.append(FIFOItemProduct(**ip)) - FIFOItemProduct.objects.bulk_create(ips) - # 创建IProduct - ips2 = [] - for i in [wproduct]: - ip = {} - ip['warehouse'] = vdata['warehouse'] - ip['batch'] = batch - ip['wproduct'] = i - ip['number'] = i.number - ip['material'] = material - ips2.append(IProduct(**ip)) - IProduct.objects.bulk_create(ips2) - # 更新库存并修改半成品进行状态 - update_inm(fifo) - wproduct.act_state=WProduct.WPR_ACT_STATE_INM - wproduct.warehouse=vdata['warehouse'] - wproduct.save() - return Response() - class WProductViewSet(ListModelMixin, GenericViewSet): """ 半成品 @@ -235,6 +178,63 @@ class WProductViewSet(ListModelMixin, GenericViewSet): return Response() + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer) + @transaction.atomic + def putin(self, request, pk=None): + """ + 半成品入库 + """ + serializer= WproductPutInSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.data + wproduct = self.get_object() + if wproduct.act_state != WProduct.WPR_ACT_STATE_OK: + raise exceptions.APIException('半成品不可入库') + material = wproduct.m_state + batch = wproduct.production_plan.number + # 创建入库记录 + remark = vdata.get('remark', '') + fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN, + is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark) + # 创建入库明细 + fifoitem = FIFOItem() + fifoitem.is_tested = True + fifoitem.is_testok = True + fifoitem.warehouse = vdata['warehouse'] + fifoitem.material = material + fifoitem.count = 1 # 单个半成品入库 + fifoitem.batch = batch + fifoitem.fifo = fifo + fifoitem.subproduction_plan = wproduct.subproduction_plan + fifoitem.save() + # 创建入库明细半成品 + ips = [] + for i in [wproduct]: + ip = {} + ip['fifoitem'] = fifoitem + ip['wproduct'] = i + ip['number'] = i.number + ip['material'] = material + ips.append(FIFOItemProduct(**ip)) + FIFOItemProduct.objects.bulk_create(ips) + # 创建IProduct + ips2 = [] + for i in [wproduct]: + ip = {} + ip['warehouse'] = vdata['warehouse'] + ip['batch'] = batch + ip['wproduct'] = i + ip['number'] = i.number + ip['material'] = material + ips2.append(IProduct(**ip)) + IProduct.objects.bulk_create(ips2) + # 更新库存并修改半成品进行状态 + update_inm(fifo) + wproduct.act_state=WProduct.WPR_ACT_STATE_INM + wproduct.warehouse=vdata['warehouse'] + wproduct.save() + return Response() + class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet): """ 生产操作记录 From 3df4c68f4740765feddca1858d896d7e704283bd Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 16 Nov 2021 16:56:44 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=A3=80=E6=B5=8Bbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/serializers.py | 29 +++++++++++++++++++++++++++-- hb_server/apps/wpm/views.py | 2 +- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 5c9a3e0..8653bde 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -1,6 +1,6 @@ from rest_framework import serializers, exceptions from rest_framework.serializers import ModelSerializer -from apps.inm.models import FIFO, FIFOItem, MaterialBatch, WareHouse +from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse from apps.inm.signals import update_inm from apps.mtm.models import Material, RecordForm, Step from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer @@ -18,6 +18,8 @@ class PickDetailSerializer(serializers.Serializer): batch = serializers.CharField(label='物料批次', allow_blank=True) warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") pick_count = serializers.IntegerField(label="领料数量", required=False) + iproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all()), label='库存半成品ID', + required=False) class PickSerializer(serializers.Serializer): subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID") @@ -38,16 +40,33 @@ class PickSerializer(serializers.Serializer): # except: # raise exceptions.ValidationError('物料不存在') # 创建出库记录 + with transaction.atomic(): fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), create_by=self.context['request'].user) for i in picks: # 更新出库详情 i['count'] = i.pop('pick_count', 0) + # 是否勾选每一个 + if 'iproducts' in i and len(i['iproducts'])>0: + i['count'] = len(i['iproducts']) + isLowLevel = True if i['count']>0: i['fifo'] = fifo i['is_testok'] = True # 默认检测合格 i['subproduction_plan'] = sp - FIFOItem.objects.create(**i) + fifoitem = FIFOItem.objects.create(**i) + # 创建再下一个层级 + if isLowLevel: + mls = [] + for m in i['iproducts']: + ml = {} + ml['material'] = m.material + ml['number'] = m.number + ml['wproduct'] = m.wproduct + ml['fifoitem'] = fifoitem + mls.append(FIFOItemProduct(**ml)) + FIFOItemProduct.objects.bulk_create(mls) + # 更新车间物料 wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \ subproduction_plan=sp,defaults={ @@ -62,6 +81,12 @@ class PickSerializer(serializers.Serializer): spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1) spp.count_pick = spp.count_pick + i['count'] spp.save() + # 更新半成品表 + wproducts = WProduct.objects.filter(pk__in=[x.wproduct for x in i['iproducts']]) + first_step = Step.objects.get(pk=sp.steps[0].id) + wproducts.update(p_state=first_step, is_executed=False, + act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None, + subproduction_plan=sp, production_plan=sp.production_plan) sp.is_picked=True sp.state = 3 #生产中 sp.state_date_real = timezone.now() #实际开工日期 diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index a1875a3..8c929c9 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -168,7 +168,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): wproduct.save() # 更新子计划状态 # 获取该子计划主产品数, 更新进度 - main_count = WProduct.objects.filter(subproduction_plan=wproduct.subproduction_plan, act_stae=WProduct.WPR_ACT_STATE_OK).count() + main_count = WProduct.objects.filter(subproduction_plan=wproduct.subproduction_plan, act_state=WProduct.WPR_ACT_STATE_OK).count() instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) instance.count_real = main_count From 43d297881e279da6e1f04c4398e882d464a19c46 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Tue, 16 Nov 2021 17:08:32 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E6=A3=80=E6=B5=8Bbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/wpm/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 8c929c9..8652c4b 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -24,6 +24,7 @@ from rest_framework import exceptions, serializers from apps.wpm.services import WpmServies from django.utils import timezone +import uuid # Create your views here. class WPlanViewSet(ListModelMixin, GenericViewSet): """ @@ -164,7 +165,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): if obj.is_testok: wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.number is None: # 产生半成品编号 - wproduct.number = 'BCP' + str(timezone.now()) + wproduct.number = uuid.uuid4() wproduct.save() # 更新子计划状态 # 获取该子计划主产品数, 更新进度 From 7e8ce5d60ac65ce51d26ab172e37b5aeec00fae0 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 17 Nov 2021 09:56:58 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E5=8D=95=E4=B8=AA=E5=8D=8A=E6=88=90?= =?UTF-8?q?=E5=93=81=E5=85=A5=E5=BA=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/pm/views.py | 3 ++- hb_server/apps/wpm/serializers.py | 8 +++++-- hb_server/apps/wpm/views.py | 37 ++++++++++++++++++++++--------- hb_server/utils/tools.py | 7 ++++++ 4 files changed, 42 insertions(+), 13 deletions(-) create mode 100644 hb_server/utils/tools.py diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py index a718880..2128aab 100644 --- a/hb_server/apps/pm/views.py +++ b/hb_server/apps/pm/views.py @@ -17,6 +17,7 @@ from rest_framework.exceptions import APIException from rest_framework.response import Response from rest_framework.decorators import action from django.db.models import F +from utils.tools import ranstr # Create your views here. def updateOrderPlanedCount(order): @@ -59,7 +60,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel pass else: raise APIException('排产数量错误') - instance = serializer.save(create_by=request.user, product=order.product) + instance = serializer.save(create_by=request.user, product=order.product, number='JH-'+ranstr(7)) updateOrderPlanedCount(instance.order) return Response() diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py index 8653bde..c5bae06 100644 --- a/hb_server/apps/wpm/serializers.py +++ b/hb_server/apps/wpm/serializers.py @@ -13,17 +13,21 @@ from apps.system.serializers import UserSimpleSerializer from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, OperationRecordItem from django.db import transaction +class PickHalfSerializer(serializers.Serializer): + wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID'), + required=False) # 从半成品表里直接修改状态 class PickDetailSerializer(serializers.Serializer): material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID") batch = serializers.CharField(label='物料批次', allow_blank=True) warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID") pick_count = serializers.IntegerField(label="领料数量", required=False) - iproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all()), label='库存半成品ID', + iproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=IProduct.objects.all(), label='库存半成品ID'), required=False) class PickSerializer(serializers.Serializer): subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID") - picks = PickDetailSerializer(many=True) + picks = PickDetailSerializer(many=True) # 从库存里拿 + def create(self, validated_data): picks = validated_data.pop('picks') diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index 8652c4b..d81c071 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -5,7 +5,7 @@ from rest_framework.utils import serializer_helpers from rest_framework.utils.field_mapping import get_relation_kwargs from rest_framework.views import APIView from rest_framework.viewsets import GenericViewSet, ModelViewSet -from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct +from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse from apps.inm.signals import update_inm from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial from apps.mtm.serializers import RecordFormDetailSerializer @@ -17,14 +17,14 @@ from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from rest_framework.decorators import action from apps.wpm.models import WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem -from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer +from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer from rest_framework.response import Response from django.db import transaction from rest_framework import exceptions, serializers from apps.wpm.services import WpmServies from django.utils import timezone -import uuid +from utils.tools import ranstr # Create your views here. class WPlanViewSet(ListModelMixin, GenericViewSet): """ @@ -38,6 +38,21 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): ordering_fields = [] ordering = ['-id'] + @action(methods=['post', 'get'], detail=True, perms_map={'post':'*', 'get':'*'}, serializer_class=PickHalfSerializer) + @transaction.atomic + def pick_half(self, request, pk=None): + """ + 领半成品 + """ + # if request.method=='GET' + # subplan = self.get_object() + # serializer= PickHalfSerializer(data=request.data) + # serializer.is_valid(raise_exception=True) + # vdata = serializer.data + # wps = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']]) + # pass + + @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WplanPutInSerializer) @transaction.atomic def putin(self, request, pk=None): @@ -50,6 +65,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): subplan = self.get_object() material = subplan.main_product batch = subplan.production_plan.number + warehouse = WareHouse.objects.get(id=vdata['warehouse']) wproducts = WProduct.objects.filter(subproduction_plan=subplan, act_state=WProduct.WPR_ACT_STATE_OK, m_state=material, is_deleted=False) if wproducts.exists(): @@ -61,7 +77,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): fifoitem = FIFOItem() fifoitem.is_tested = True fifoitem.is_testok = True - fifoitem.warehouse = vdata['warehouse'] + fifoitem.warehouse = warehouse fifoitem.material = material fifoitem.count = wproducts.count() fifoitem.batch = batch @@ -82,7 +98,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): ips2 = [] for i in wproducts: ip = {} - ip['warehouse'] = vdata['warehouse'] + ip['warehouse'] = warehouse ip['batch'] = batch ip['wproduct'] = i ip['number'] = i.number @@ -91,7 +107,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): IProduct.objects.bulk_create(ips2) # 更新库存并修改半成品进行状态 update_inm(fifo) - wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=vdata['warehouse']) + wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse) return Response() @@ -165,7 +181,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): if obj.is_testok: wproduct.act_state = WProduct.WPR_ACT_STATE_OK if wproduct.number is None: # 产生半成品编号 - wproduct.number = uuid.uuid4() + wproduct.number = 'WP-'+ranstr(7) wproduct.save() # 更新子计划状态 # 获取该子计划主产品数, 更新进度 @@ -189,6 +205,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): serializer.is_valid(raise_exception=True) vdata = serializer.data wproduct = self.get_object() + warehouse = WareHouse.objects.get(id=vdata['warehouse']) if wproduct.act_state != WProduct.WPR_ACT_STATE_OK: raise exceptions.APIException('半成品不可入库') material = wproduct.m_state @@ -201,7 +218,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): fifoitem = FIFOItem() fifoitem.is_tested = True fifoitem.is_testok = True - fifoitem.warehouse = vdata['warehouse'] + fifoitem.warehouse = warehouse fifoitem.material = material fifoitem.count = 1 # 单个半成品入库 fifoitem.batch = batch @@ -222,7 +239,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): ips2 = [] for i in [wproduct]: ip = {} - ip['warehouse'] = vdata['warehouse'] + ip['warehouse'] = warehouse ip['batch'] = batch ip['wproduct'] = i ip['number'] = i.number @@ -232,7 +249,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet): # 更新库存并修改半成品进行状态 update_inm(fifo) wproduct.act_state=WProduct.WPR_ACT_STATE_INM - wproduct.warehouse=vdata['warehouse'] + wproduct.warehouse=warehouse wproduct.save() return Response() diff --git a/hb_server/utils/tools.py b/hb_server/utils/tools.py new file mode 100644 index 0000000..786b8f2 --- /dev/null +++ b/hb_server/utils/tools.py @@ -0,0 +1,7 @@ +import random +import string + +def ranstr(num): + salt = ''.join(random.sample(string.ascii_letters + string.digits, num)) + return salt +ranstr(10) \ No newline at end of file From ac7c06eb646eae34c6754d13a4a1d18196564e33 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 17 Nov 2021 10:08:59 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=8D=8A=E6=88=90=E5=93=81=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/urls.py | 3 ++- hb_server/apps/inm/views.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/inm/urls.py b/hb_server/apps/inm/urls.py index 908d9b6..b0dbbd1 100644 --- a/hb_server/apps/inm/urls.py +++ b/hb_server/apps/inm/urls.py @@ -1,6 +1,6 @@ from django.db.models import base from rest_framework import urlpatterns -from apps.inm.views import FIFOItemViewSet, FIFOViewSet, MaterialBatchViewSet, WarehouseViewSet,InventoryViewSet +from apps.inm.views import FIFOItemViewSet, FIFOViewSet, IProductViewSet, MaterialBatchViewSet, WarehouseViewSet,InventoryViewSet from django.urls import path, include from rest_framework.routers import DefaultRouter @@ -10,6 +10,7 @@ router.register('inventory', InventoryViewSet, basename='inventory') router.register('materialbatch', MaterialBatchViewSet, basename='materialbatch') router.register('fifo', FIFOViewSet, basename='fifo'), router.register('fifoitem', FIFOItemViewSet, basename='fifoitem') +router.register('iproduct', IProductViewSet, basename='iproduct') urlpatterns = [ path('', include(router.urls)), ] diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index c05693e..eccb166 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -169,7 +169,7 @@ class IProductViewSet(ListModelMixin, GenericViewSet): perms_map = {'*': '*'} queryset = IProduct.objects.select_related('material', 'warehouse').all() serializer_class = IProductListSerializer - filterset_fields = ['material', 'warehouse'] + filterset_fields = ['material', 'warehouse', 'batch'] search_fields = [] ordering_fields = ['create_time'] ordering = ['-create_time'] \ No newline at end of file From 5b22d2c993e0d70225331615babb53718cfa4ccb Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 17 Nov 2021 10:08:59 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E5=BA=93=E5=AD=98=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=8D=8A=E6=88=90=E5=93=81=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hb_server/apps/inm/urls.py | 3 ++- hb_server/apps/inm/views.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hb_server/apps/inm/urls.py b/hb_server/apps/inm/urls.py index 908d9b6..b0dbbd1 100644 --- a/hb_server/apps/inm/urls.py +++ b/hb_server/apps/inm/urls.py @@ -1,6 +1,6 @@ from django.db.models import base from rest_framework import urlpatterns -from apps.inm.views import FIFOItemViewSet, FIFOViewSet, MaterialBatchViewSet, WarehouseViewSet,InventoryViewSet +from apps.inm.views import FIFOItemViewSet, FIFOViewSet, IProductViewSet, MaterialBatchViewSet, WarehouseViewSet,InventoryViewSet from django.urls import path, include from rest_framework.routers import DefaultRouter @@ -10,6 +10,7 @@ router.register('inventory', InventoryViewSet, basename='inventory') router.register('materialbatch', MaterialBatchViewSet, basename='materialbatch') router.register('fifo', FIFOViewSet, basename='fifo'), router.register('fifoitem', FIFOItemViewSet, basename='fifoitem') +router.register('iproduct', IProductViewSet, basename='iproduct') urlpatterns = [ path('', include(router.urls)), ] diff --git a/hb_server/apps/inm/views.py b/hb_server/apps/inm/views.py index c05693e..eccb166 100644 --- a/hb_server/apps/inm/views.py +++ b/hb_server/apps/inm/views.py @@ -169,7 +169,7 @@ class IProductViewSet(ListModelMixin, GenericViewSet): perms_map = {'*': '*'} queryset = IProduct.objects.select_related('material', 'warehouse').all() serializer_class = IProductListSerializer - filterset_fields = ['material', 'warehouse'] + filterset_fields = ['material', 'warehouse', 'batch'] search_fields = [] ordering_fields = ['create_time'] ordering = ['-create_time'] \ No newline at end of file From ace7d222c8eb9b44cbd5a3ecf691cd8e3bac06a8 Mon Sep 17 00:00:00 2001 From: caoqianming Date: Wed, 17 Nov 2021 14:39:16 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E5=BA=93=E5=AD=98=E5=8D=8A=E6=88=90?= =?UTF-8?q?=E5=93=81=E5=88=97=E8=A1=A8=E6=A0=B9=E6=8D=AE=E5=87=BA=E5=85=A5?= =?UTF-8?q?=E5=BA=93=E8=AE=B0=E5=BD=95=E5=8F=98=E5=8A=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../migrations/0017_alter_iproduct_number.py | 19 +++++++++ hb_server/apps/inm/models.py | 2 +- hb_server/apps/inm/signals.py | 19 ++++++++- hb_server/apps/pm/models.py | 2 + hb_server/apps/pm/signals.py | 2 +- hb_server/apps/wpm/models.py | 3 +- hb_server/apps/wpm/views.py | 42 +++++++++---------- 7 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 hb_server/apps/inm/migrations/0017_alter_iproduct_number.py diff --git a/hb_server/apps/inm/migrations/0017_alter_iproduct_number.py b/hb_server/apps/inm/migrations/0017_alter_iproduct_number.py new file mode 100644 index 0000000..0e3931c --- /dev/null +++ b/hb_server/apps/inm/migrations/0017_alter_iproduct_number.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.6 on 2021-11-17 06:38 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('inm', '0016_auto_20211112_1124'), + ] + + operations = [ + migrations.AlterField( + model_name='iproduct', + name='number', + field=models.CharField(default=1, max_length=50, unique=True, verbose_name='物品编号'), + preserve_default=False, + ), + ] diff --git a/hb_server/apps/inm/models.py b/hb_server/apps/inm/models.py index c3902bf..57e3e17 100644 --- a/hb_server/apps/inm/models.py +++ b/hb_server/apps/inm/models.py @@ -97,7 +97,7 @@ class IProduct(BaseModel): """ 具体产品条目 """ - number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50) + number = models.CharField('物品编号', unique=True, max_length=50) material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE) warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库') batch = models.CharField('所属批次号', max_length=100, default='') diff --git a/hb_server/apps/inm/signals.py b/hb_server/apps/inm/signals.py index 66870a4..79d5a19 100644 --- a/hb_server/apps/inm/signals.py +++ b/hb_server/apps/inm/signals.py @@ -1,7 +1,7 @@ from django.db.models.signals import post_save from django.dispatch import receiver -from apps.inm.models import FIFOItemProduct, Inventory, MaterialBatch, FIFO, FIFOItem +from apps.inm.models import FIFOItemProduct, IProduct, Inventory, MaterialBatch, FIFO, FIFOItem def update_inm(instance:FIFO, type:int=1): @@ -23,6 +23,19 @@ def update_inm(instance:FIFO, type:int=1): o2.save() material.count = material.count + i.count material.save() + + # 创建IProduct + ips2 = [] + for m in FIFOItemProduct.objects.filter(fifoitem=i): + ip = {} + ip['warehouse'] = warehouse + ip['batch'] = i.batch + ip['wproduct'] = m.wproduct + ip['number'] = m.number + ip['material'] = m.material + ips2.append(IProduct(**ip)) + IProduct.objects.bulk_create(ips2) + elif instance.type in [FIFO.FIFO_TYPE_DO_OUT]: # 生产领料 # 更新相关表 for i in FIFOItem.objects.filter(fifo=instance): @@ -36,4 +49,8 @@ def update_inm(instance:FIFO, type:int=1): o2.save() material.count = material.count - i.count material.save() + + # 删除IProduct + numbers = FIFOItemProduct.objects.filter(fifoitem=i).values_list('number', flat=True) + IProduct.objects.filter(number__in=numbers).delete() diff --git a/hb_server/apps/pm/models.py b/hb_server/apps/pm/models.py index bc59ec9..ddddd78 100644 --- a/hb_server/apps/pm/models.py +++ b/hb_server/apps/pm/models.py @@ -57,6 +57,8 @@ class SubProductionPlan(CommonAModel): start_date_real = models.DateField('实际开工日期', null=True, blank=True) end_date_real = models.DateField('实际完工日期', null=True, blank=True) is_picked = models.BooleanField('是否已领料', default=False) + + # wproducts = models.JSONField('半成品表', default=list, blank=True) class Meta: verbose_name = '子生产计划' verbose_name_plural = verbose_name diff --git a/hb_server/apps/pm/signals.py b/hb_server/apps/pm/signals.py index 9d6cd6c..b07a67c 100644 --- a/hb_server/apps/pm/signals.py +++ b/hb_server/apps/pm/signals.py @@ -13,7 +13,7 @@ def update_subplan_main(sender, instance, created, **kwargs): subplan.main_product = instance.material subplan.main_count = instance.count subplan.main_count_real = instance.count_real - if subplan.main_count == instance.count_real: + if subplan.main_count >= instance.count_real: subplan.state = 4 subplan.save() diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py index 83dfcf1..7424783 100644 --- a/hb_server/apps/wpm/models.py +++ b/hb_server/apps/wpm/models.py @@ -20,7 +20,7 @@ class WMaterial(BaseModel): class WProduct(CommonAModel): """ - 半成品/成品 + 动态半成品/成品表 """ WPR_ACT_STATE_DOING = 1 WPR_ACT_STATE_TOTEST = 2 @@ -45,7 +45,6 @@ class WProduct(CommonAModel): production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE) warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True) - class Operation(CommonAModel): """ 生产操作 diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py index d81c071..7a5f9c3 100644 --- a/hb_server/apps/wpm/views.py +++ b/hb_server/apps/wpm/views.py @@ -44,13 +44,25 @@ class WPlanViewSet(ListModelMixin, GenericViewSet): """ 领半成品 """ - # if request.method=='GET' - # subplan = self.get_object() - # serializer= PickHalfSerializer(data=request.data) - # serializer.is_valid(raise_exception=True) - # vdata = serializer.data - # wps = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']]) - # pass + sp = self.get_object() + if request.method=='GET': + """ + 领半成品 + """ + mIds = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN, + material__type=Material.MA_TYPE_HALFGOOD).values_list('material', flat=True) + queyset = WProduct.objects.filter(is_hidden=False, m_state__in=mIds, act_state=WProduct.WPR_ACT_STATE_OK) + return Response(WProductListSerializer(instance=queyset, many=True).data) + elif request.method=='POST': + serializer= PickHalfSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + vdata = serializer.data + wps = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']]) + first_step = Step.objects.get(pk=sp.steps[0].id) + wps.update(p_state=first_step, is_executed=False, + act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None, + subproduction_plan=sp, production_plan=sp.production_plan) + return Response() @action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WplanPutInSerializer) @@ -184,11 +196,10 @@ class WProductViewSet(ListModelMixin, GenericViewSet): wproduct.number = 'WP-'+ranstr(7) wproduct.save() # 更新子计划状态 - # 获取该子计划主产品数, 更新进度 - main_count = WProduct.objects.filter(subproduction_plan=wproduct.subproduction_plan, act_state=WProduct.WPR_ACT_STATE_OK).count() + # 更新子计划主产品数 instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) - instance.count_real = main_count + instance.count_real = instance.count_real + 1 # 这个地方可能会有问题 instance.save() else:# 如果不合格 pass @@ -235,17 +246,6 @@ class WProductViewSet(ListModelMixin, GenericViewSet): ip['material'] = material ips.append(FIFOItemProduct(**ip)) FIFOItemProduct.objects.bulk_create(ips) - # 创建IProduct - ips2 = [] - for i in [wproduct]: - ip = {} - ip['warehouse'] = warehouse - ip['batch'] = batch - ip['wproduct'] = i - ip['number'] = i.number - ip['material'] = material - ips2.append(IProduct(**ip)) - IProduct.objects.bulk_create(ips2) # 更新库存并修改半成品进行状态 update_inm(fifo) wproduct.act_state=WProduct.WPR_ACT_STATE_INM