Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
91d82a7882
|
@ -66,7 +66,7 @@
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
|
||||||
<el-card style="margin-top: 6px">
|
<el-card style="margin-top: 2px">
|
||||||
<div slot="header" class="clearfix">
|
<div slot="header" class="clearfix">
|
||||||
<span>日志列表</span>
|
<span>日志列表</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 01:51
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0028_auto_20211102_1707'),
|
||||||
|
('qm', '0003_testrecord'),
|
||||||
|
('inm', '0010_auto_20211102_1631'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name='FIFODetail',
|
||||||
|
new_name='FIFOItem',
|
||||||
|
),
|
||||||
|
]
|
|
@ -53,11 +53,15 @@ class FIFO(CommonAModel):
|
||||||
"""
|
"""
|
||||||
出入库记录
|
出入库记录
|
||||||
"""
|
"""
|
||||||
|
FIFO_TYPE_DO_OUT = 1 # 生产领料
|
||||||
|
FIFO_TYPE_SALE_OUT = 2
|
||||||
|
FIFO_TYPE_PUR_IN = 3
|
||||||
|
FIFO_TYPE_DO_IN = 4
|
||||||
type_choices = (
|
type_choices = (
|
||||||
(1, '生产领料'),
|
(FIFO_TYPE_DO_OUT, '生产领料'),
|
||||||
(2, '销售提货'),
|
(FIFO_TYPE_SALE_OUT, '销售提货'),
|
||||||
(3, '采购入库'),
|
(FIFO_TYPE_PUR_IN, '采购入库'),
|
||||||
(4, '生产入库')
|
(FIFO_TYPE_DO_IN, '生产入库')
|
||||||
)
|
)
|
||||||
type = models.IntegerField('出入库类型', default=1)
|
type = models.IntegerField('出入库类型', default=1)
|
||||||
is_audited = models.BooleanField('是否审核', default=False)
|
is_audited = models.BooleanField('是否审核', default=False)
|
||||||
|
@ -68,9 +72,9 @@ class FIFO(CommonAModel):
|
||||||
remark = models.CharField('备注', max_length=1000, default='')
|
remark = models.CharField('备注', max_length=1000, default='')
|
||||||
|
|
||||||
|
|
||||||
class FIFODetail(BaseModel):
|
class FIFOItem(BaseModel):
|
||||||
"""
|
"""
|
||||||
出入库详细记录
|
出入库详细条目
|
||||||
"""
|
"""
|
||||||
is_tested = models.BooleanField('是否已检测', default=False)
|
is_tested = models.BooleanField('是否已检测', default=False)
|
||||||
is_testok = models.BooleanField('是否检测合格', default=False)
|
is_testok = models.BooleanField('是否检测合格', default=False)
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from apps.inm.models import FIFO, FIFODetail, IProduct, MaterialBatch, WareHouse,Inventory
|
from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory
|
||||||
|
|
||||||
from apps.system.serializers import UserSimpleSerializer
|
from apps.system.serializers import UserSimpleSerializer
|
||||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
class WareHouseSerializer(serializers. ModelSerializer):
|
class WareHouseSerializer(serializers. ModelSerializer):
|
||||||
create_by_=UserSimpleSerializer('create_by', read_only=True)
|
create_by_=UserSimpleSerializer('create_by', read_only=True)
|
||||||
|
@ -42,10 +43,10 @@ class FIFOListSerializer(serializers.ModelSerializer):
|
||||||
model=FIFO
|
model=FIFO
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
class FIFODetailSerializer(serializers.ModelSerializer):
|
class FIFOItemSerializer(serializers.ModelSerializer):
|
||||||
material_= MaterialSimpleSerializer(source='material', read_only=True)
|
material_= MaterialSimpleSerializer(source='material', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model=FIFODetail
|
model= FIFOItem
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
class IProductInPurSerializer(serializers.ModelSerializer):
|
class IProductInPurSerializer(serializers.ModelSerializer):
|
||||||
|
@ -56,7 +57,7 @@ class IProductInPurSerializer(serializers.ModelSerializer):
|
||||||
class FIFODetailInPurSerializer(serializers.ModelSerializer):
|
class FIFODetailInPurSerializer(serializers.ModelSerializer):
|
||||||
details = IProductInPurSerializer(many=True, required=False)
|
details = IProductInPurSerializer(many=True, required=False)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FIFODetail
|
model = FIFOItem
|
||||||
fields = ['material', 'count', 'batch', 'details']
|
fields = ['material', 'count', 'batch', 'details']
|
||||||
|
|
||||||
class MaterialBatchQuerySerializer(serializers.Serializer):
|
class MaterialBatchQuerySerializer(serializers.Serializer):
|
||||||
|
@ -91,7 +92,8 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# 创建采购入库
|
# 创建采购入库
|
||||||
validated_data['type'] = 3
|
with transaction.atomic():
|
||||||
|
validated_data['type'] = FIFO.FIFO_TYPE_PUR_IN
|
||||||
obj = FIFO(**validated_data)
|
obj = FIFO(**validated_data)
|
||||||
obj.save()
|
obj.save()
|
||||||
for i in details:
|
for i in details:
|
||||||
|
@ -101,7 +103,7 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
||||||
raise serializers.ValidationError('数目对不上')
|
raise serializers.ValidationError('数目对不上')
|
||||||
else:
|
else:
|
||||||
i['fifo'] = obj
|
i['fifo'] = obj
|
||||||
fifod = FIFODetail.objects.create(**i)
|
fifod = FIFOItem.objects.create(**i)
|
||||||
p_list = []
|
p_list = []
|
||||||
for x in p_details:
|
for x in p_details:
|
||||||
x['state'] = 1
|
x['state'] = 1
|
||||||
|
@ -113,6 +115,6 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
||||||
IProduct.objects.bulk_create(p_list)
|
IProduct.objects.bulk_create(p_list)
|
||||||
else:
|
else:
|
||||||
i['fifo'] = obj
|
i['fifo'] = obj
|
||||||
FIFODetail.objects.create(**i)
|
FIFOItem.objects.create(**i)
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from apps.inm.models import Inventory, MaterialBatch, FIFO, FIFODetail
|
from apps.inm.models import Inventory, MaterialBatch, FIFO, FIFOItem
|
||||||
|
|
||||||
|
|
||||||
def update_inm(instance:FIFO, type:int=1):
|
def update_inm(instance:FIFO, type:int=1):
|
||||||
|
@ -9,9 +9,9 @@ def update_inm(instance:FIFO, type:int=1):
|
||||||
更新库存(正反)
|
更新库存(正反)
|
||||||
"""
|
"""
|
||||||
warehouse = instance.warehouse
|
warehouse = instance.warehouse
|
||||||
if instance.type in [3]: # 采购入库
|
if instance.type in [FIFO.FIFO_TYPE_PUR_IN]: # 采购入库
|
||||||
# 更新相关表
|
# 更新相关表
|
||||||
for i in FIFODetail.objects.filter(fifo=instance):
|
for i in FIFOItem.objects.filter(fifo=instance):
|
||||||
material = i.material
|
material = i.material
|
||||||
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
|
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
|
||||||
defaults={'material':material, 'warehouse':warehouse, 'count':0})
|
defaults={'material':material, 'warehouse':warehouse, 'count':0})
|
||||||
|
@ -23,9 +23,9 @@ def update_inm(instance:FIFO, type:int=1):
|
||||||
o2.save()
|
o2.save()
|
||||||
material.count = material.count + i.count
|
material.count = material.count + i.count
|
||||||
material.save()
|
material.save()
|
||||||
elif instance.type in [1]: # 生产领料
|
elif instance.type in [FIFO.FIFO_TYPE_DO_OUT]: # 生产领料
|
||||||
# 更新相关表
|
# 更新相关表
|
||||||
for i in FIFODetail.objects.filter(fifo=instance):
|
for i in FIFOItem.objects.filter(fifo=instance):
|
||||||
material = i.material
|
material = i.material
|
||||||
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
|
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
|
||||||
o1.count = o1.count - i.count
|
o1.count = o1.count - i.count
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db.models import base
|
from django.db.models import base
|
||||||
from rest_framework import urlpatterns
|
from rest_framework import urlpatterns
|
||||||
from apps.inm.views import FIFODetailViewSet, FIFOViewSet, MaterialBatchViewSet, WarehouseViewSet,InventoryViewSet
|
from apps.inm.views import FIFOItemViewSet, FIFOViewSet, MaterialBatchViewSet, WarehouseViewSet,InventoryViewSet
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ router.register('warehouse', WarehouseViewSet, basename='warehouse')
|
||||||
router.register('inventory', InventoryViewSet, basename='inventory')
|
router.register('inventory', InventoryViewSet, basename='inventory')
|
||||||
router.register('materialbatch', MaterialBatchViewSet, basename='materialbatch')
|
router.register('materialbatch', MaterialBatchViewSet, basename='materialbatch')
|
||||||
router.register('fifo', FIFOViewSet, basename='fifo'),
|
router.register('fifo', FIFOViewSet, basename='fifo'),
|
||||||
router.register('fifodetail', FIFODetailViewSet, basename='fifodetail')
|
router.register('fifodetail', FIFOItemViewSet, basename='fifodetail')
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.exceptions import APIException
|
from rest_framework.exceptions import APIException
|
||||||
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
|
from rest_framework.mixins import DestroyModelMixin, ListModelMixin, RetrieveModelMixin
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||||
from apps.inm.filters import MbFilterSet
|
from apps.inm.filters import MbFilterSet
|
||||||
|
|
||||||
from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse,Inventory
|
from apps.inm.models import FIFO, FIFOItem, MaterialBatch, WareHouse,Inventory
|
||||||
from apps.inm.serializers import FIFODetailSerializer, FIFOInPurSerializer, FIFOListSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
|
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
|
||||||
from apps.inm.signals import update_inm
|
from apps.inm.signals import update_inm
|
||||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
class WarehouseViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||||
|
@ -63,18 +64,23 @@ class MaterialBatchViewSet(ListModelMixin, GenericViewSet):
|
||||||
queryset = self.queryset.filter(warehouse__id=data['warehouse'], material__id__in=data['materials'])
|
queryset = self.queryset.filter(warehouse__id=data['warehouse'], material__id__in=data['materials'])
|
||||||
return Response(MaterialBatchSerializer(instance=queryset, many=True).data)
|
return Response(MaterialBatchSerializer(instance=queryset, many=True).data)
|
||||||
|
|
||||||
class FIFODetailViewSet(ListModelMixin, GenericViewSet):
|
class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
出入库记录详情表
|
出入库记录详情表
|
||||||
"""
|
"""
|
||||||
perms_map = {'*': '*'}
|
perms_map = {'*': '*'}
|
||||||
queryset = FIFODetail.objects.select_related('material', 'fifo').all()
|
queryset = FIFOItem.objects.select_related('material', 'fifo').all()
|
||||||
serializer_class = FIFODetailSerializer
|
serializer_class = FIFOItemSerializer
|
||||||
filterset_fields = ['material', 'fifo']
|
filterset_fields = ['material', 'fifo']
|
||||||
search_fields = []
|
search_fields = []
|
||||||
ordering_fields = ['create_time']
|
ordering_fields = ['create_time']
|
||||||
ordering = ['-create_time']
|
ordering = ['-create_time']
|
||||||
|
|
||||||
|
def perform_destroy(self, instance):
|
||||||
|
if instance.fifo.is_audited:
|
||||||
|
raise APIException('该出入库记录已通过审核, 无法删除')
|
||||||
|
return super().perform_destroy(instance)
|
||||||
|
|
||||||
class FIFOViewSet(ListModelMixin, GenericViewSet):
|
class FIFOViewSet(ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
出入库记录
|
出入库记录
|
||||||
|
@ -108,9 +114,12 @@ class FIFOViewSet(ListModelMixin, GenericViewSet):
|
||||||
审核通过
|
审核通过
|
||||||
"""
|
"""
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
for i in FIFODetail.objects.filter(fifo=obj):
|
for i in FIFOItem.objects.filter(fifo=obj):
|
||||||
if not i.is_testok:
|
if not i.is_testok:
|
||||||
raise APIException('未检验通过, 不可审核')
|
raise APIException('未检验通过, 不可审核')
|
||||||
|
if obj.is_audited:
|
||||||
|
raise APIException('该入库记录已审核通过')
|
||||||
|
with transaction.atomic():
|
||||||
obj.is_audited = True
|
obj.is_audited = True
|
||||||
obj.save()
|
obj.save()
|
||||||
update_inm(obj) # 更新库存
|
update_inm(obj) # 更新库存
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 09:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0028_auto_20211102_1707'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='step',
|
||||||
|
name='type',
|
||||||
|
field=models.IntegerField(choices=[(1, '普通'), (2, '分割'), (3, '结合')], default=1, verbose_name='操作类型'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -12,13 +12,19 @@ class Material(CommonAModel):
|
||||||
"""
|
"""
|
||||||
物料
|
物料
|
||||||
"""
|
"""
|
||||||
|
MA_TYPE_GOOD = 1
|
||||||
|
MA_TYPE_HALFGOOD = 2
|
||||||
|
MA_TYPE_MAINSO = 3
|
||||||
|
MA_TYPE_HELPSO = 4
|
||||||
|
MA_TYPE_TOOL = 5
|
||||||
|
MA_TYPE_HELPTOOL = 6
|
||||||
type_choices=(
|
type_choices=(
|
||||||
(1, '成品'),
|
(MA_TYPE_GOOD, '成品'),
|
||||||
(2, '半成品'),
|
(MA_TYPE_HALFGOOD, '半成品'),
|
||||||
(3, '主要原料'),
|
(MA_TYPE_MAINSO, '主要原料'),
|
||||||
(4, '辅助材料') ,
|
(MA_TYPE_HELPSO, '辅助材料') ,
|
||||||
(5, '加工工具'),
|
(MA_TYPE_TOOL, '加工工具'),
|
||||||
(6, '辅助工装')
|
(MA_TYPE_HELPTOOL, '辅助工装')
|
||||||
)
|
)
|
||||||
unit_choices =(
|
unit_choices =(
|
||||||
('块', '块'),
|
('块', '块'),
|
||||||
|
@ -62,6 +68,15 @@ class Step(CommonAModel):
|
||||||
"""
|
"""
|
||||||
工序步骤
|
工序步骤
|
||||||
"""
|
"""
|
||||||
|
STEP_TYPE_NOM = 1
|
||||||
|
STEP_TYPE_DIV = 2
|
||||||
|
STEP_TYPE_COMB = 3
|
||||||
|
step_type_choices=(
|
||||||
|
(STEP_TYPE_NOM, '普通'),
|
||||||
|
(STEP_TYPE_DIV, '分割'),
|
||||||
|
(STEP_TYPE_COMB, '结合')
|
||||||
|
)
|
||||||
|
type = models.IntegerField('操作类型', choices=step_type_choices, default=1)
|
||||||
process = models.ForeignKey(Process, on_delete=models.CASCADE, verbose_name='所属工序', related_name='step_process')
|
process = models.ForeignKey(Process, on_delete=models.CASCADE, verbose_name='所属工序', related_name='step_process')
|
||||||
name = models.CharField('工序步骤名称', max_length=100)
|
name = models.CharField('工序步骤名称', max_length=100)
|
||||||
number = models.CharField('步骤编号', max_length=100, null=True, blank=True)
|
number = models.CharField('步骤编号', max_length=100, null=True, blank=True)
|
||||||
|
@ -80,9 +95,11 @@ class RecordForm(CommonAModel):
|
||||||
"""
|
"""
|
||||||
记录表格
|
记录表格
|
||||||
"""
|
"""
|
||||||
|
RF_TYPE_DO = 1
|
||||||
|
RF_TYPE_TEST = 2
|
||||||
type_choices=(
|
type_choices=(
|
||||||
(1, '生产记录'),
|
(RF_TYPE_DO, '生产记录'),
|
||||||
(2, '检验记录')
|
(RF_TYPE_TEST, '检验记录')
|
||||||
)
|
)
|
||||||
name = models.CharField('表格名称', max_length=100, unique=True)
|
name = models.CharField('表格名称', max_length=100, unique=True)
|
||||||
type = models.IntegerField('表格类型', choices=type_choices, default=1)
|
type = models.IntegerField('表格类型', choices=type_choices, default=1)
|
||||||
|
@ -164,10 +181,13 @@ class SubprodctionMaterial(CommonAModel):
|
||||||
"""
|
"""
|
||||||
输入/输出物料/工具工装
|
输入/输出物料/工具工装
|
||||||
"""
|
"""
|
||||||
|
SUB_MA_TYPE_IN = 1
|
||||||
|
SUB_MA_TYPE_OUT = 2
|
||||||
|
SUB_MA_TYPE_TOOL = 3
|
||||||
type_choices=(
|
type_choices=(
|
||||||
(1, '输入物料'),
|
(SUB_MA_TYPE_IN, '输入物料'),
|
||||||
(2, '输出物料'),
|
(SUB_MA_TYPE_OUT, '输出物料'),
|
||||||
(3, '工具工装')
|
(SUB_MA_TYPE_TOOL, '工具工装')
|
||||||
)
|
)
|
||||||
material = models.ForeignKey(Material, verbose_name='物料', on_delete=models.CASCADE, related_name='subplan_material')
|
material = models.ForeignKey(Material, verbose_name='物料', on_delete=models.CASCADE, related_name='subplan_material')
|
||||||
is_main = models.BooleanField('是否主产出', default=False) # 以该产品完成度计算进度
|
is_main = models.BooleanField('是否主产出', default=False) # 以该产品完成度计算进度
|
||||||
|
|
|
@ -61,6 +61,11 @@ class StepDetailSerializer(serializers.ModelSerializer):
|
||||||
queryset = queryset.prefetch_related('equipments')
|
queryset = queryset.prefetch_related('equipments')
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
class SubProductionSimpleSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = SubProduction
|
||||||
|
fields = ['id', 'name']
|
||||||
|
|
||||||
class SubProductionSerializer(serializers.ModelSerializer):
|
class SubProductionSerializer(serializers.ModelSerializer):
|
||||||
process_ = ProcessSimpleSerializer(source='process', read_only=True)
|
process_ = ProcessSimpleSerializer(source='process', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -90,9 +95,9 @@ class InputMaterialSerializer(serializers.ModelSerializer):
|
||||||
fields = ['count', 'sort', 'material', 'subproduction']
|
fields = ['count', 'sort', 'material', 'subproduction']
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
if SubprodctionMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=1).exists():
|
if SubprodctionMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=SubprodctionMaterial.SUB_MA_TYPE_IN).exists():
|
||||||
raise ValidationError('该物料已存在')
|
raise ValidationError('该物料已存在')
|
||||||
validated_data['type']=1
|
validated_data['type']=SubprodctionMaterial.SUB_MA_TYPE_IN
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
class InputMaterialUpdateSerializer(serializers.ModelSerializer):
|
class InputMaterialUpdateSerializer(serializers.ModelSerializer):
|
||||||
|
@ -106,11 +111,11 @@ class OutputMaterialSerializer(serializers.ModelSerializer):
|
||||||
fields = ['count', 'sort', 'material', 'subproduction', 'is_main']
|
fields = ['count', 'sort', 'material', 'subproduction', 'is_main']
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
if SubprodctionMaterial.objects.filter(subproduction=validated_data['subproduction'], is_deleted=False, is_main=True, type=2).exists():
|
if SubprodctionMaterial.objects.filter(subproduction=validated_data['subproduction'], is_deleted=False, is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT).exists():
|
||||||
raise ValidationError('主产出只能有1个')
|
raise ValidationError('主产出只能有1个')
|
||||||
if SubprodctionMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=2).exists():
|
if SubprodctionMaterial.objects.filter(material=validated_data['material'], subproduction=validated_data['subproduction'], is_deleted=False, type=SubprodctionMaterial.SUB_MA_TYPE_OUT).exists():
|
||||||
raise ValidationError('该物料已存在')
|
raise ValidationError('该物料已存在')
|
||||||
validated_data['type']=2
|
validated_data['type']=SubprodctionMaterial.SUB_MA_TYPE_OUT
|
||||||
return super().create(validated_data)
|
return super().create(validated_data)
|
||||||
|
|
||||||
class OutputMaterialUpdateSerializer(serializers.ModelSerializer):
|
class OutputMaterialUpdateSerializer(serializers.ModelSerializer):
|
||||||
|
|
|
@ -85,7 +85,7 @@ class InputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||||
输入物料-增删改查
|
输入物料-增删改查
|
||||||
"""
|
"""
|
||||||
perms_map = {'*':'*'}
|
perms_map = {'*':'*'}
|
||||||
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=1)
|
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN)
|
||||||
serializer_class = InputMaterialSerializer
|
serializer_class = InputMaterialSerializer
|
||||||
filterset_fields = ['subproduction']
|
filterset_fields = ['subproduction']
|
||||||
ordering = ['sort', '-create_time']
|
ordering = ['sort', '-create_time']
|
||||||
|
@ -102,7 +102,7 @@ class OutputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||||
输出物料-增删改查
|
输出物料-增删改查
|
||||||
"""
|
"""
|
||||||
perms_map = {'*':'*'}
|
perms_map = {'*':'*'}
|
||||||
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=2)
|
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
||||||
serializer_class = OutputMaterialSerializer
|
serializer_class = OutputMaterialSerializer
|
||||||
filterset_fields = ['subproduction']
|
filterset_fields = ['subproduction']
|
||||||
ordering = ['sort', '-create_time']
|
ordering = ['sort', '-create_time']
|
||||||
|
@ -119,7 +119,7 @@ class OtherMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, DestroyModel
|
||||||
其他物料-增删改查
|
其他物料-增删改查
|
||||||
"""
|
"""
|
||||||
perms_map = {'*':'*'}
|
perms_map = {'*':'*'}
|
||||||
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=3)
|
queryset = SubprodctionMaterial.objects.select_related('material').filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL)
|
||||||
serializer_class = OutputMaterialSerializer
|
serializer_class = OutputMaterialSerializer
|
||||||
filterset_fields = ['subproduction']
|
filterset_fields = ['subproduction']
|
||||||
ordering = ['sort', '-create_time']
|
ordering = ['sort', '-create_time']
|
||||||
|
|
|
@ -5,3 +5,5 @@ class SamConfig(AppConfig):
|
||||||
verbose_name = '生产计划管理'
|
verbose_name = '生产计划管理'
|
||||||
|
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
import apps.pm.signals
|
|
@ -0,0 +1,53 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-03 09:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0028_auto_20211102_1707'),
|
||||||
|
('pm', '0009_auto_20211029_1017'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subproductionplan',
|
||||||
|
name='main_count',
|
||||||
|
field=models.IntegerField(default=1, verbose_name='应产出数'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subproductionplan',
|
||||||
|
name='main_count_real',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='实际产出数'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subproductionplan',
|
||||||
|
name='main_product',
|
||||||
|
field=models.ForeignKey(default=19, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='主要产品'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subproductionprogress',
|
||||||
|
name='count_pick',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='实际领用数'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='subproductionprogress',
|
||||||
|
name='is_main',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='是否主产出'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='subproductionprogress',
|
||||||
|
name='count',
|
||||||
|
field=models.IntegerField(verbose_name='应出入数'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='subproductionprogress',
|
||||||
|
name='count_real',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='实际消耗/产出数'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-04 02:06
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0028_auto_20211102_1707'),
|
||||||
|
('pm', '0010_auto_20211103_1700'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='subproductionplan',
|
||||||
|
name='main_count',
|
||||||
|
field=models.IntegerField(default=0, verbose_name='应产出数'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='subproductionplan',
|
||||||
|
name='main_product',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='主要产品'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 09:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pm', '0011_auto_20211104_1006'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='subproductionprogress',
|
||||||
|
name='type',
|
||||||
|
field=models.IntegerField(default=((1, '输入物料'), (2, '输出物料'), (3, '工具工装')), verbose_name='物料应用类型'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -7,7 +7,7 @@ import django.utils.timezone as timezone
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
from utils.model import SoftModel, BaseModel
|
from utils.model import SoftModel, BaseModel
|
||||||
from apps.mtm.models import Material, Process, SubProduction
|
from apps.mtm.models import Material, Process, SubProduction, SubprodctionMaterial
|
||||||
from apps.sam.models import Order
|
from apps.sam.models import Order
|
||||||
|
|
||||||
class ProductionPlan(CommonAModel):
|
class ProductionPlan(CommonAModel):
|
||||||
|
@ -43,9 +43,16 @@ class SubProductionPlan(CommonAModel):
|
||||||
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
|
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
|
||||||
start_date = models.DateField('计划开工日期')
|
start_date = models.DateField('计划开工日期')
|
||||||
end_date = models.DateField('计划完工日期')
|
end_date = models.DateField('计划完工日期')
|
||||||
|
|
||||||
workshop = models.ForeignKey(Organization, 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)
|
process = models.ForeignKey(Process, verbose_name='关联大工序', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
main_product = models.ForeignKey(Material, verbose_name='主要产品', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
main_count = models.IntegerField('应产出数', default=0)
|
||||||
|
main_count_real = models.IntegerField('实际产出数', default=0)
|
||||||
|
|
||||||
steps = models.JSONField('工艺步骤', default=list)
|
steps = models.JSONField('工艺步骤', default=list)
|
||||||
|
|
||||||
state = models.IntegerField('状态', default=0)
|
state = models.IntegerField('状态', default=0)
|
||||||
start_date_real = models.DateField('实际开工日期', null=True, blank=True)
|
start_date_real = models.DateField('实际开工日期', null=True, blank=True)
|
||||||
end_date_real = models.DateField('实际完工日期', null=True, blank=True)
|
end_date_real = models.DateField('实际完工日期', null=True, blank=True)
|
||||||
|
@ -58,13 +65,10 @@ class SubProductionProgress(BaseModel):
|
||||||
"""
|
"""
|
||||||
子计划生产进度统计表/物料消耗
|
子计划生产进度统计表/物料消耗
|
||||||
"""
|
"""
|
||||||
type_choices=(
|
|
||||||
(1, '输入物料'),
|
|
||||||
(2, '输出物料'),
|
|
||||||
(3, '工具工装')
|
|
||||||
)
|
|
||||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, related_name='progress_subplan')
|
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, related_name='progress_subplan')
|
||||||
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
|
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
|
||||||
type = models.IntegerField('物料应用类型', default=1)
|
is_main = models.BooleanField('是否主产出', default=False)
|
||||||
count = models.FloatField('应出入数')
|
type = models.IntegerField('物料应用类型', default=SubprodctionMaterial.type_choices)
|
||||||
count_real = models.IntegerField('实际出入数', default=0)
|
count = models.IntegerField('应出入数')
|
||||||
|
count_pick = models.IntegerField('实际领用数', default=0)
|
||||||
|
count_real = models.IntegerField('实际消耗/产出数', default=0)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
|
from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from apps.sam.serializers import OrderSerializer
|
from apps.sam.serializers import OrderSerializer
|
||||||
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer
|
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, SubProductionSimpleSerializer
|
||||||
from apps.system.serializers import OrganizationSimpleSerializer
|
from apps.system.serializers import OrganizationSimpleSerializer
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,10 +27,15 @@ class ResourceCalListSerializer(serializers.ListSerializer):
|
||||||
class SubProductionPlanListSerializer(serializers.ModelSerializer):
|
class SubProductionPlanListSerializer(serializers.ModelSerializer):
|
||||||
workshop_ = OrganizationSimpleSerializer(source='workshop', read_only=True)
|
workshop_ = OrganizationSimpleSerializer(source='workshop', read_only=True)
|
||||||
process_ = ProcessSimpleSerializer(source='process', read_only=True)
|
process_ = ProcessSimpleSerializer(source='process', read_only=True)
|
||||||
|
subproduction_ = SubProductionSimpleSerializer(source='subproduction', read_only=True)
|
||||||
|
main_product_ = MaterialSimpleSerializer(source='main_product', read_only=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model=SubProductionPlan
|
model=SubProductionPlan
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SubProductionPlanUpdateSerializer(serializers.ModelSerializer):
|
class SubProductionPlanUpdateSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SubProductionPlan
|
model = SubProductionPlan
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from apps.pm.models import SubProductionProgress
|
||||||
|
|
||||||
|
@receiver(post_save, sender=SubProductionProgress)
|
||||||
|
def update_subplan_main(sender, instance, created, **kwargs):
|
||||||
|
"""
|
||||||
|
根据生产进度统计表更新子计划进度表相关字段
|
||||||
|
"""
|
||||||
|
if instance.is_main:
|
||||||
|
subplan = instance.subproduction_plan
|
||||||
|
if created:
|
||||||
|
subplan.main_product = instance.material
|
||||||
|
subplan.main_count = instance.count
|
||||||
|
subplan.main_count_real = instance.count_real
|
||||||
|
subplan.save()
|
||||||
|
|
||||||
|
|
|
@ -87,8 +87,11 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
|
||||||
start_date=production_plan.start_date, end_date=production_plan.end_date,
|
start_date=production_plan.start_date, end_date=production_plan.end_date,
|
||||||
workshop=i.process.workshop, process=i.process, create_by=request.user,
|
workshop=i.process.workshop, process=i.process, create_by=request.user,
|
||||||
steps = list(steps))
|
steps = list(steps))
|
||||||
|
# 生成子计划物料需求/进度
|
||||||
for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
|
for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
|
||||||
SubProductionProgress.objects.create(material=m.material, type=m.type, count=m.count*production_plan.count, subproduction_plan=instance)
|
spro = SubProductionProgress.objects.create(material=m.material, type=m.type,
|
||||||
|
is_main=m.is_main,
|
||||||
|
count=m.count*production_plan.count, subproduction_plan=instance)
|
||||||
production_plan.is_planed=True
|
production_plan.is_planed=True
|
||||||
production_plan.save()
|
production_plan.save()
|
||||||
return Response()
|
return Response()
|
||||||
|
@ -98,10 +101,10 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
|
||||||
子生产计划-列表/修改
|
子生产计划-列表/修改
|
||||||
"""
|
"""
|
||||||
perms_map = {'*': '*'}
|
perms_map = {'*': '*'}
|
||||||
queryset = SubProductionPlan.objects.select_related('process', 'workshop')
|
queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'main_product')
|
||||||
search_fields = []
|
search_fields = []
|
||||||
serializer_class = SubProductionPlanListSerializer
|
serializer_class = SubProductionPlanListSerializer
|
||||||
filterset_fields = ['production_plan', 'process', 'state']
|
filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop']
|
||||||
ordering_fields = ['process__number']
|
ordering_fields = ['process__number']
|
||||||
ordering = ['process__number']
|
ordering = ['process__number']
|
||||||
|
|
||||||
|
@ -152,7 +155,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
|
||||||
领料需求清单
|
领料需求清单
|
||||||
"""
|
"""
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=1)
|
instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
|
||||||
serializer = SubProductionProgressSerializer(instance=instance, many=True)
|
serializer = SubProductionProgressSerializer(instance=instance, many=True)
|
||||||
return Response(serializer.data)
|
return Response(serializer.data)
|
||||||
|
|
||||||
|
@ -162,7 +165,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
|
||||||
领料需求清单/库存数
|
领料需求清单/库存数
|
||||||
"""
|
"""
|
||||||
obj = self.get_object()
|
obj = self.get_object()
|
||||||
instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=1)
|
instance = SubProductionProgress.objects.filter(subproduction_plan=obj, type=SubprodctionMaterial.SUB_MA_TYPE_IN)
|
||||||
serializer = SubProductionProgressSerializer(instance=instance, many=True)
|
serializer = SubProductionProgressSerializer(instance=instance, many=True)
|
||||||
need = serializer.data
|
need = serializer.data
|
||||||
materials = []
|
materials = []
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 01:51
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0028_auto_20211102_1707'),
|
||||||
|
('qm', '0003_testrecord'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='testrecord',
|
||||||
|
old_name='fifo_detail',
|
||||||
|
new_name='fifo_item',
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='TestRecordItem',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('field_name', models.CharField(max_length=50, verbose_name='字段名')),
|
||||||
|
('field_key', models.CharField(max_length=50, verbose_name='字段标识')),
|
||||||
|
('field_type', models.IntegerField(choices=[(1, '生产记录'), (2, '检验记录')], verbose_name='字段类型')),
|
||||||
|
('field_value', models.JSONField(blank=True, default=dict, verbose_name='录入值')),
|
||||||
|
('need_judge', models.BooleanField(default=False, verbose_name='是否需要判定')),
|
||||||
|
('is_testok', models.BooleanField(default=True, verbose_name='是否合格')),
|
||||||
|
('form_field', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='mtm.recordformfield', verbose_name='关联字段')),
|
||||||
|
('test_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.testrecord', verbose_name='关联的检测记录')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 03:02
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('qm', '0004_auto_20211108_0951'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='testrecord',
|
||||||
|
name='record_data',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='testrecorditem',
|
||||||
|
name='test_record',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='item_test_record', to='qm.testrecord', verbose_name='关联的检测记录'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 03:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('qm', '0005_auto_20211108_1102'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='testrecorditem',
|
||||||
|
name='sort',
|
||||||
|
field=models.IntegerField(default=1, verbose_name='排序号'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 05:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('qm', '0006_testrecorditem_sort'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='testrecorditem',
|
||||||
|
name='field_type',
|
||||||
|
field=models.CharField(choices=[(1, '生产记录'), (2, '检验记录')], max_length=50, verbose_name='字段类型'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,5 +1,8 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.db.models.enums import Choices
|
||||||
|
from apps.mtm.models import RecordForm, RecordFormField
|
||||||
from apps.system.models import CommonAModel, File
|
from apps.system.models import CommonAModel, File
|
||||||
|
from utils.model import BaseModel
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
class Standard(CommonAModel):
|
class Standard(CommonAModel):
|
||||||
"""
|
"""
|
||||||
|
@ -44,9 +47,21 @@ class TestRecord(CommonAModel):
|
||||||
"""
|
"""
|
||||||
检验记录
|
检验记录
|
||||||
"""
|
"""
|
||||||
|
|
||||||
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
|
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)
|
is_testok = models.BooleanField('是否合格', default=True)
|
||||||
fifo_detail = models.ForeignKey('inm.fifodetail', 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)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRecordItem(BaseModel):
|
||||||
|
"""
|
||||||
|
记录表格字段值
|
||||||
|
"""
|
||||||
|
form_field = models.ForeignKey(RecordFormField, verbose_name='关联字段', on_delete=models.CASCADE, db_constraint=False)
|
||||||
|
field_name = models.CharField('字段名', max_length=50)
|
||||||
|
field_key = models.CharField('字段标识', max_length=50)
|
||||||
|
field_type = models.CharField('字段类型', choices=RecordForm.type_choices, max_length=50)
|
||||||
|
field_value = models.JSONField('录入值', default=dict, blank=True)
|
||||||
|
need_judge = models.BooleanField('是否需要判定', default=False)
|
||||||
|
sort = models.IntegerField('排序号', default=1)
|
||||||
|
is_testok = models.BooleanField('是否合格', default=True)
|
||||||
|
test_record = models.ForeignKey(TestRecord, verbose_name='关联的检测记录', on_delete=models.CASCADE, related_name='item_test_record')
|
|
@ -2,7 +2,7 @@ from rest_framework import serializers
|
||||||
from apps.mtm.models import RecordForm, RecordFormField
|
from apps.mtm.models import RecordForm, RecordFormField
|
||||||
from apps.mtm.serializers import RecordFormFieldSerializer, RecordFormSimpleSerializer
|
from apps.mtm.serializers import RecordFormFieldSerializer, RecordFormSimpleSerializer
|
||||||
from apps.system.serializers import FileSimpleSerializer
|
from apps.system.serializers import FileSimpleSerializer
|
||||||
from .models import Standard, TestItem, TestRecord
|
from .models import Standard, TestItem, TestRecord, TestRecordItem
|
||||||
|
|
||||||
class StandardCreateUpdateSerializer(serializers.ModelSerializer):
|
class StandardCreateUpdateSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -35,15 +35,21 @@ class AnalysisItemSerializer(serializers.ModelSerializer):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TestRecordItemCreateSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = TestRecordItem
|
||||||
|
fields = ['form_field', 'field_value']
|
||||||
|
|
||||||
|
class TestRecordItemSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = TestRecordItem
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
class TestRecordCreateSerializer(serializers.ModelSerializer):
|
class TestRecordCreateSerializer(serializers.ModelSerializer):
|
||||||
|
record_data = TestRecordItemCreateSerializer(many=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TestRecord
|
model = TestRecord
|
||||||
fields = ['form', 'record_data', 'is_testok', 'fifo_detail']
|
fields = ['form', 'record_data', 'is_testok', 'fifo_item']
|
||||||
|
|
||||||
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 TestRecordListSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -53,21 +59,21 @@ class TestRecordListSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class TestRecordDetailSerializer(serializers.ModelSerializer):
|
class TestRecordDetailSerializer(serializers.ModelSerializer):
|
||||||
form_ = RecordFormSimpleSerializer(source='form', read_only=True)
|
form_ = RecordFormSimpleSerializer(source='form', read_only=True)
|
||||||
record_data_ = serializers.SerializerMethodField()
|
record_data_ = TestRecordItemSerializer(source='item_test_record', read_only=True, many=True)
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TestRecord
|
model = TestRecord
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def setup_eager_loading(queryset):
|
def setup_eager_loading(queryset):
|
||||||
queryset = queryset.select_related('form','fifo_detail')
|
queryset = queryset.select_related('form','fifo_item')
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
def get_record_data_(self, obj):
|
# def get_record_data_(self, obj):
|
||||||
record_data = obj.record_data
|
# record_data = obj.record_data
|
||||||
all_fields = RecordFormField.objects.filter(form=obj.form, is_deletd=False).order_by('sort')
|
# all_fields = RecordFormField.objects.filter(form=obj.form, is_deletd=False).order_by('sort')
|
||||||
all_fields_l = RecordFormFieldSerializer(instance=all_fields, many=True).data
|
# all_fields_l = RecordFormFieldSerializer(instance=all_fields, many=True).data
|
||||||
for i in all_fields_l:
|
# for i in all_fields_l:
|
||||||
key = i['field_key']
|
# key = i['field_key']
|
||||||
i['field_value'] = record_data.get(key, None)
|
# i['field_value'] = record_data.get(key, None)
|
||||||
return all_fields_l
|
# return all_fields_l
|
|
@ -1,8 +1,12 @@
|
||||||
from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer, TestRecordCreateSerializer, TestRecordDetailSerializer, TestRecordListSerializer
|
from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer, TestRecordCreateSerializer, TestRecordDetailSerializer, TestRecordListSerializer
|
||||||
from apps.qm.models import Standard, TestItem, TestRecord
|
from apps.qm.models import Standard, TestItem, TestRecord, TestRecordItem
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from rest_framework.viewsets import ModelViewSet
|
from rest_framework.viewsets import ModelViewSet
|
||||||
from apps.system.mixins import CreateUpdateModelAMixin
|
from apps.system.mixins import CreateUpdateModelAMixin
|
||||||
|
from rest_framework.exceptions import APIException
|
||||||
|
from rest_framework.response import Response
|
||||||
|
from rest_framework import status
|
||||||
|
from django.db import transaction
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
class StandardViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
class StandardViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
||||||
"""
|
"""
|
||||||
|
@ -43,7 +47,7 @@ class TestRecordViewSet(ModelViewSet):
|
||||||
检测记录
|
检测记录
|
||||||
"""
|
"""
|
||||||
perms_map = {'*': '*'}
|
perms_map = {'*': '*'}
|
||||||
queryset = TestRecord.objects.select_related('fifo_detail', 'form').all()
|
queryset = TestRecord.objects.select_related('fifo_item', 'form').all()
|
||||||
serializer_class = TestRecordListSerializer
|
serializer_class = TestRecordListSerializer
|
||||||
ordering = ['-id']
|
ordering = ['-id']
|
||||||
|
|
||||||
|
@ -56,10 +60,33 @@ class TestRecordViewSet(ModelViewSet):
|
||||||
return TestRecordDetailSerializer
|
return TestRecordDetailSerializer
|
||||||
return super().get_serializer_class()
|
return super().get_serializer_class()
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def create(self, request, *args, **kwargs):
|
||||||
|
serializer = self.get_serializer(data=request.data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.validated_data
|
||||||
|
record_data = vdata.pop('record_data')
|
||||||
|
if 'is_testok' not in vdata:
|
||||||
|
raise APIException('未填写检测结论')
|
||||||
|
with transaction.atomic():
|
||||||
obj = serializer.save(create_by = self.request.user)
|
obj = serializer.save(create_by = self.request.user)
|
||||||
|
tris = []
|
||||||
|
for m in record_data: # 保存记录详情
|
||||||
|
form_field = m['form_field']
|
||||||
|
m['field_name'] = form_field.field_name
|
||||||
|
m['field_key'] = form_field.field_key
|
||||||
|
m['field_type'] = form_field.field_type
|
||||||
|
m['field_value'] = m['field_value']
|
||||||
|
m['sort'] = form_field.sort
|
||||||
|
m['need_judge'] = form_field.need_judge
|
||||||
|
m['is_testok'] = m['is_testok'] if 'is_testok' in m else True
|
||||||
|
m['test_record'] = obj
|
||||||
|
tris.append(TestRecordItem(**m))
|
||||||
|
TestRecordItem.objects.bulk_create(tris)
|
||||||
|
|
||||||
# 如果检测合格
|
# 如果检测合格
|
||||||
if obj.fifo_detail:
|
if obj.fifo_item:
|
||||||
obj.fifo_detail.is_testok = True if obj.is_testok else False
|
obj.fifo_item.is_testok = True if obj.is_testok else False
|
||||||
obj.fifo_detail.is_tested = True
|
obj.fifo_item.is_tested = True
|
||||||
obj.fifo_detail.save()
|
obj.fifo_item.save()
|
||||||
|
|
||||||
|
return Response(status=status.HTTP_201_CREATED)
|
|
@ -30,7 +30,6 @@ class Migration(migrations.Migration):
|
||||||
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproduct_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproduct_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
('m_state', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所属物料状态')),
|
('m_state', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所属物料状态')),
|
||||||
('p_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='所在步骤')),
|
('p_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='所在步骤')),
|
||||||
('parent', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='上一级')),
|
|
||||||
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子生产计划')),
|
('subproduction_plan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子生产计划')),
|
||||||
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproduct_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproduct_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
],
|
],
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-04 01:14
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('pm', '0010_auto_20211103_1700'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('mtm', '0028_auto_20211102_1707'),
|
||||||
|
('wpm', '0003_auto_20211102_0935'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='WProductRecord',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('data', models.JSONField(blank=True, default=dict, verbose_name='记录的数据')),
|
||||||
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
|
('record_form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.recordform', verbose_name='所用表格')),
|
||||||
|
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wmaterial',
|
||||||
|
name='process',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wmaterial',
|
||||||
|
name='workshop',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductflow',
|
||||||
|
name='wproduct',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wmaterial',
|
||||||
|
name='subproduction_plan',
|
||||||
|
field=models.ForeignKey(default=68, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子计划'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproductflow',
|
||||||
|
name='wproducts',
|
||||||
|
field=models.JSONField(default=list, verbose_name='关联产品'),
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='WProductForm',
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,109 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 01:01
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('mtm', '0028_auto_20211102_1707'),
|
||||||
|
('wpm', '0004_auto_20211104_0914'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='WProductAction',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('wproducts', models.JSONField(blank=True, default=list, verbose_name='关联产品ID列表')),
|
||||||
|
('remark', models.CharField(blank=True, max_length=200, null=True, verbose_name='操作备注')),
|
||||||
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductaction_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
|
('m_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='操作时的物料状态')),
|
||||||
|
('p_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='操作步骤')),
|
||||||
|
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductaction_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='WProductMaterial',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('type', models.IntegerField(choices=[(1, '消耗'), (2, '产出')], default=0, verbose_name='类型')),
|
||||||
|
('count', models.IntegerField(verbose_name='消耗或产出数量')),
|
||||||
|
('material', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='可能产出的副产品')),
|
||||||
|
('wmaterial', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wmaterial', verbose_name='关联的车间物料')),
|
||||||
|
('wproduct_action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.wproductaction', verbose_name='关联的生产操作')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='WProductRecordDetail',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('field_name', models.CharField(max_length=50, verbose_name='字段名')),
|
||||||
|
('field_key', models.CharField(max_length=50, verbose_name='字段标识')),
|
||||||
|
('field_type', models.IntegerField(choices=[(1, '生产记录'), (2, '检验记录')], verbose_name='字段类型')),
|
||||||
|
('field_value', models.JSONField(blank=True, default=dict, verbose_name='录入值')),
|
||||||
|
('sort', models.IntegerField(default=1, verbose_name='排序号')),
|
||||||
|
('form_field', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='mtm.recordformfield', verbose_name='关联字段')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='WProductFlow',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductrecord',
|
||||||
|
name='data',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductrecord',
|
||||||
|
name='record_form',
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproduct',
|
||||||
|
name='is_executed',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='子工序是否已执行'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproductrecord',
|
||||||
|
name='form',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='mtm.recordform', verbose_name='所用的生产记录表格'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='wproduct',
|
||||||
|
name='act_state',
|
||||||
|
field=models.IntegerField(choices=[(1, '生产中'), (2, '待检测'), (3, '已合格')], default=0, verbose_name='进行状态'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproductrecorddetail',
|
||||||
|
name='wproduct_record',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.wproductrecord', verbose_name='关联的生产记录'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproductrecord',
|
||||||
|
name='wproduct_action',
|
||||||
|
field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproductaction', verbose_name='关联的生产操作'),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 01:35
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0028_auto_20211102_1707'),
|
||||||
|
('wpm', '0005_auto_20211108_0901'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameModel(
|
||||||
|
old_name='WProductRecordDetail',
|
||||||
|
new_name='WProductRecordItem',
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 05:05
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wpm', '0006_rename_wproductrecorddetail_wproductrecorditem'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='wproductrecorditem',
|
||||||
|
name='field_type',
|
||||||
|
field=models.CharField(choices=[(1, '生产记录'), (2, '检验记录')], max_length=50, verbose_name='字段类型'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 09:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wpm', '0007_alter_wproductrecorditem_field_type'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproduct',
|
||||||
|
name='is_hidden',
|
||||||
|
field=models.BooleanField(default=False, verbose_name='是否隐藏'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 15:07
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wpm', '0008_wproduct_is_hidden'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='wproduct',
|
||||||
|
name='parent',
|
||||||
|
field=models.JSONField(blank=True, default=list, verbose_name='父'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,136 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-08 15:35
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('mtm', '0029_step_type'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
('wpm', '0009_wproduct_parent'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='Operation',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('wproducts', models.JSONField(blank=True, default=list, verbose_name='关联产品ID列表')),
|
||||||
|
('remark', models.CharField(blank=True, max_length=200, null=True, verbose_name='操作备注')),
|
||||||
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operation_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
|
('m_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='操作时的物料状态')),
|
||||||
|
('p_state', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.step', verbose_name='操作步骤')),
|
||||||
|
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operation_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OperationMaterial',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('type', models.IntegerField(choices=[(1, '消耗'), (2, '产出')], default=0, verbose_name='类型')),
|
||||||
|
('count', models.IntegerField(verbose_name='消耗或产出数量')),
|
||||||
|
('material', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='可能产出的副产品')),
|
||||||
|
('operation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.operation', verbose_name='关联的生产操作')),
|
||||||
|
('wmaterial', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wmaterial', verbose_name='关联的车间物料')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OperationRecord',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operationrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
|
||||||
|
('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.recordform', verbose_name='所用的生产记录表格')),
|
||||||
|
('operation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.operation', verbose_name='关联的生产操作')),
|
||||||
|
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='operationrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='OperationRecordItem',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
|
||||||
|
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
|
||||||
|
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
|
||||||
|
('field_name', models.CharField(max_length=50, verbose_name='字段名')),
|
||||||
|
('field_key', models.CharField(max_length=50, verbose_name='字段标识')),
|
||||||
|
('field_type', models.CharField(choices=[(1, '生产记录'), (2, '检验记录')], max_length=50, verbose_name='字段类型')),
|
||||||
|
('field_value', models.JSONField(blank=True, default=dict, verbose_name='录入值')),
|
||||||
|
('sort', models.IntegerField(default=1, verbose_name='排序号')),
|
||||||
|
('form_field', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='mtm.recordformfield', verbose_name='关联字段')),
|
||||||
|
('operation_record', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.operation', verbose_name='关联的生产记录')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductmaterial',
|
||||||
|
name='material',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductmaterial',
|
||||||
|
name='wmaterial',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductmaterial',
|
||||||
|
name='wproduct_action',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductrecord',
|
||||||
|
name='create_by',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductrecord',
|
||||||
|
name='form',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductrecord',
|
||||||
|
name='update_by',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductrecord',
|
||||||
|
name='wproduct_action',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductrecorditem',
|
||||||
|
name='form_field',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wproductrecorditem',
|
||||||
|
name='wproduct_record',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='WProductAction',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='WProductMaterial',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='WProductRecord',
|
||||||
|
),
|
||||||
|
migrations.DeleteModel(
|
||||||
|
name='WProductRecordItem',
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.2.6 on 2021-11-09 05:44
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('wpm', '0010_auto_20211108_2335'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='operationrecorditem',
|
||||||
|
name='operation_record',
|
||||||
|
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.operationrecord', verbose_name='关联的生产记录'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -6,14 +6,13 @@ from apps.pm.models import ProductionPlan, SubProductionPlan
|
||||||
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
|
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
|
||||||
from utils.model import SoftModel, BaseModel
|
from utils.model import SoftModel, BaseModel
|
||||||
from simple_history.models import HistoricalRecords
|
from simple_history.models import HistoricalRecords
|
||||||
from apps.mtm.models import Material, Process, Step, RecordForm
|
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm
|
||||||
|
|
||||||
class WMaterial(BaseModel):
|
class WMaterial(BaseModel):
|
||||||
"""
|
"""
|
||||||
车间生产物料
|
车间生产物料
|
||||||
"""
|
"""
|
||||||
workshop = models.ForeignKey(Organization, verbose_name='生产车间', on_delete=models.CASCADE)
|
subproduction_plan = models.ForeignKey(SubProductionPlan, 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)
|
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
|
||||||
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
|
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
|
||||||
count = models.IntegerField('当前数量', default=0)
|
count = models.IntegerField('当前数量', default=0)
|
||||||
|
@ -22,30 +21,66 @@ class WProduct(CommonAModel):
|
||||||
"""
|
"""
|
||||||
半成品/成品
|
半成品/成品
|
||||||
"""
|
"""
|
||||||
|
WPR_ACT_STATE_DOING = 1
|
||||||
|
WPR_ACT_STATE_TOTEST = 2
|
||||||
|
WPR_ACT_STATE_OK = 3
|
||||||
act_state_choices=(
|
act_state_choices=(
|
||||||
(0, '待执行'),
|
(WPR_ACT_STATE_DOING, '生产中'),
|
||||||
(1, '进行中'),
|
(WPR_ACT_STATE_TOTEST, '待检测'),
|
||||||
(2, '已完成')
|
(WPR_ACT_STATE_OK, '已合格')
|
||||||
)
|
)
|
||||||
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
|
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
|
||||||
m_state = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
m_state = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
|
||||||
p_state = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True)
|
p_state = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
act_state = models.IntegerField('进行状态', default=0)
|
act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices)
|
||||||
parent = models.ForeignKey('self', verbose_name='上一级', on_delete=models.CASCADE, db_constraint=False)
|
is_executed = models.BooleanField('子工序是否已执行', default=False)
|
||||||
|
is_hidden = models.BooleanField('是否隐藏', default=False)
|
||||||
|
parent = models.JSONField('父', default=list, blank=True)
|
||||||
remark = models.CharField('备注', max_length=200, null=True, blank=True)
|
remark = models.CharField('备注', max_length=200, null=True, blank=True)
|
||||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
|
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
|
||||||
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
|
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
|
||||||
|
|
||||||
class WProductForm(CommonAModel):
|
|
||||||
|
class Operation(CommonAModel):
|
||||||
|
"""
|
||||||
|
生产操作
|
||||||
|
"""
|
||||||
|
wproducts = models.JSONField('关联产品ID列表', default=list, blank=True)
|
||||||
|
m_state = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
p_state = models.ForeignKey(Step, verbose_name='操作步骤', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
remark = models.CharField('操作备注', max_length=200, null=True, blank=True)
|
||||||
|
|
||||||
|
class OperationMaterial(BaseModel):
|
||||||
|
"""
|
||||||
|
车间生产物料消耗产出表
|
||||||
|
"""
|
||||||
|
type_choices=(
|
||||||
|
(1, '消耗'),
|
||||||
|
(2, '产出')
|
||||||
|
)
|
||||||
|
type = models.IntegerField('类型', default=0, choices=type_choices)
|
||||||
|
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
|
||||||
|
wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
material = models.ForeignKey(Material, verbose_name='可能产出的副产品', on_delete=models.CASCADE, null=True, blank=True)
|
||||||
|
count = models.IntegerField('消耗或产出数量')
|
||||||
|
|
||||||
|
class OperationRecord(CommonAModel):
|
||||||
"""
|
"""
|
||||||
记录表格
|
记录表格
|
||||||
"""
|
"""
|
||||||
record_form = models.ForeignKey(RecordForm, verbose_name='所用表格', on_delete=models.CASCADE)
|
form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE)
|
||||||
data = models.JSONField('记录的数据', default=dict, blank=True)
|
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
|
||||||
class WProductFlow(BaseModel):
|
class OperationRecordItem(BaseModel):
|
||||||
"""
|
"""
|
||||||
产品流转日志
|
记录表格字段值
|
||||||
"""
|
"""
|
||||||
wproduct = models.ForeignKey(WProduct, verbose_name='产品', on_delete=models.CASCADE)
|
form_field = models.ForeignKey(RecordFormField, verbose_name='关联字段', on_delete=models.CASCADE, db_constraint=False)
|
||||||
|
field_name = models.CharField('字段名', max_length=50)
|
||||||
|
field_key = models.CharField('字段标识', max_length=50)
|
||||||
|
field_type = models.CharField('字段类型', choices=RecordForm.type_choices, max_length=50)
|
||||||
|
field_value = models.JSONField('录入值', default=dict, blank=True)
|
||||||
|
sort = models.IntegerField('排序号', default=1)
|
||||||
|
operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse
|
from apps.inm.models import FIFO, FIFOItem, MaterialBatch, WareHouse
|
||||||
from apps.inm.signals import update_inm
|
from apps.inm.signals import update_inm
|
||||||
from apps.mtm.models import Material
|
from apps.mtm.models import Material, RecordForm, Step
|
||||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer
|
||||||
|
|
||||||
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
from apps.wpm.models import WMaterial
|
from apps.system.serializers import UserSimpleSerializer
|
||||||
|
from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, OperationRecordItem
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
class PickDetailSerializer(serializers.Serializer):
|
class PickDetailSerializer(serializers.Serializer):
|
||||||
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
|
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
|
||||||
|
@ -23,6 +25,8 @@ class PickSerializer(serializers.Serializer):
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
picks = validated_data.pop('picks')
|
picks = validated_data.pop('picks')
|
||||||
sp = validated_data['subproduction_plan']
|
sp = validated_data['subproduction_plan']
|
||||||
|
if sp.state not in [1,2]:
|
||||||
|
raise serializers.ValidationError('该子计划状态错误')
|
||||||
if sp.is_picked:
|
if sp.is_picked:
|
||||||
raise serializers.ValidationError('该子计划已领料')
|
raise serializers.ValidationError('该子计划已领料')
|
||||||
for i in picks:
|
for i in picks:
|
||||||
|
@ -33,33 +37,36 @@ class PickSerializer(serializers.Serializer):
|
||||||
except:
|
except:
|
||||||
raise serializers.ValidationError('物料不存在')
|
raise serializers.ValidationError('物料不存在')
|
||||||
# 创建出库记录
|
# 创建出库记录
|
||||||
|
with transaction.atomic():
|
||||||
operator = self.context['request'].user
|
operator = self.context['request'].user
|
||||||
validated_data['create_by'] = operator
|
validated_data['create_by'] = operator
|
||||||
validated_data['operator'] = operator
|
validated_data['operator'] = operator
|
||||||
validated_data['type'] = 1
|
validated_data['type'] = FIFO.FIFO_TYPE_DO_OUT
|
||||||
validated_data['inout_date'] = timezone.now()
|
validated_data['inout_date'] = timezone.now()
|
||||||
fifo = FIFO.objects.create(**validated_data)
|
fifo = FIFO.objects.create(**validated_data)
|
||||||
for i in picks:
|
for i in picks:
|
||||||
# 更新出库详情
|
# 更新出库详情
|
||||||
i['fifo'] = fifo
|
i['fifo'] = fifo
|
||||||
i['count'] = i.pop('pick_count')
|
i['count'] = i.pop('pick_count')
|
||||||
FIFODetail.objects.create(**i)
|
i['is_testok'] = True # 默认检测合格
|
||||||
|
FIFOItem.objects.create(**i)
|
||||||
# 更新车间物料
|
# 更新车间物料
|
||||||
wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
|
wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
|
||||||
process=sp.process,defaults={
|
subproduction_plan=sp,defaults={
|
||||||
'material':i['material'],
|
'material':i['material'],
|
||||||
'batch':i['batch'],
|
'batch':i['batch'],
|
||||||
'process':sp.process,
|
'subproduction_plan':sp,
|
||||||
'workshop':sp.workshop,
|
|
||||||
'count':0
|
'count':0
|
||||||
})
|
})
|
||||||
wm.count = wm.count + i['count']
|
wm.count = wm.count + i['count']
|
||||||
wm.save()
|
wm.save()
|
||||||
# 更新子计划物料情况
|
# 更新子计划物料情况
|
||||||
spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1)
|
spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1)
|
||||||
spp.count_real = spp.count_real + i['count']
|
spp.count_pick = spp.count_pick + i['count']
|
||||||
spp.save()
|
spp.save()
|
||||||
sp.is_picked=True
|
sp.is_picked=True
|
||||||
|
sp.state = 3 #生产中
|
||||||
|
sp.state_date_real = timezone.now() #实际开工日期
|
||||||
sp.save()
|
sp.save()
|
||||||
# 更新库存
|
# 更新库存
|
||||||
fifo.is_audited = True
|
fifo.is_audited = True
|
||||||
|
@ -75,3 +82,98 @@ class WMaterialListSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WMaterial
|
model = WMaterial
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
|
|
||||||
|
class WProductListSerializer(serializers.ModelSerializer):
|
||||||
|
"""
|
||||||
|
半成品列表
|
||||||
|
"""
|
||||||
|
m_state_ = MaterialSimpleSerializer(source='m_state', read_only=True)
|
||||||
|
p_state_ = StepSimpleSerializer(source='p_state', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = WProduct
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
class OperationDetailSerializer(serializers.ModelSerializer):
|
||||||
|
wproducts_ = serializers.SerializerMethodField()
|
||||||
|
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||||
|
m_state_ = MaterialSimpleSerializer(source='m_state', read_only=True)
|
||||||
|
p_state_ = StepSimpleSerializer(source='p_state', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = Operation
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
def get_wproducts_(self, obj):
|
||||||
|
return list(WProduct.objects.filter(id__in=obj.wproducts).values('id', 'number'))
|
||||||
|
|
||||||
|
class OperationListSerializer(serializers.ModelSerializer):
|
||||||
|
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||||
|
m_state_ = MaterialSimpleSerializer(source='m_state', read_only=True)
|
||||||
|
p_state_ = StepSimpleSerializer(source='p_state', read_only=True)
|
||||||
|
class Meta:
|
||||||
|
model = Operation
|
||||||
|
fields = '__all__'
|
||||||
|
|
||||||
|
|
||||||
|
class OperationInitSerializer(serializers.Serializer):
|
||||||
|
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
|
||||||
|
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
|
||||||
|
wproducts = serializers.ListField(child=
|
||||||
|
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
subproduction_plan = data['subproduction_plan']
|
||||||
|
step = data['step']
|
||||||
|
|
||||||
|
stepIds=[i['id'] for i in subproduction_plan.steps]
|
||||||
|
if step.id not in stepIds:
|
||||||
|
raise serializers.ValidationError('请选择正确的子工序操作')
|
||||||
|
|
||||||
|
if 'wproducts' in data and data['wproducts']:
|
||||||
|
if step.type == Step.STEP_TYPE_DIV:
|
||||||
|
raise serializers.ValidationError(_('不可进行此操作'))
|
||||||
|
for i in data['wproducts']:
|
||||||
|
if i.is_executed:
|
||||||
|
raise serializers.ValidationError('不可进行操作')
|
||||||
|
if i.subproduction_plan != subproduction_plan:
|
||||||
|
raise serializers.ValidationError('半成品所属子计划不一致')
|
||||||
|
if i.p_state != step:
|
||||||
|
raise serializers.ValidationError('半成品所属子工序不一致')
|
||||||
|
else:
|
||||||
|
if step.type != Step.STEP_TYPE_DIV:
|
||||||
|
raise serializers.ValidationError(_('请选择半成品进行操作'))
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
class DoInputSerializer(serializers.Serializer):
|
||||||
|
id = serializers.PrimaryKeyRelatedField(queryset=WMaterial.objects.all(), label='车间物料ID')
|
||||||
|
count_input = serializers.IntegerField(min_value=0, label='消耗数量')
|
||||||
|
|
||||||
|
class DoOutputSerializer(serializers.Serializer):
|
||||||
|
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label='物料ID')
|
||||||
|
count_output = serializers.IntegerField(min_value=0, label='产出数量')
|
||||||
|
|
||||||
|
class OperationRecordItemSerializer(serializers.ModelSerializer):
|
||||||
|
class Meta:
|
||||||
|
model = OperationRecordItem
|
||||||
|
fields = ['form_field', 'field_value']
|
||||||
|
|
||||||
|
class OperationRecordSerializer(serializers.ModelSerializer):
|
||||||
|
record_data = OperationRecordItemSerializer(many=True)
|
||||||
|
class Meta:
|
||||||
|
model = OperationRecord
|
||||||
|
fields = ['form', 'record_data']
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class OperationSubmitSerializer(serializers.Serializer):
|
||||||
|
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
|
||||||
|
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
|
||||||
|
wproducts = serializers.ListField(child=
|
||||||
|
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
|
||||||
|
input = DoInputSerializer(many=True, required=False)
|
||||||
|
output = DoOutputSerializer(many=True, required=False)
|
||||||
|
forms = OperationRecordSerializer(many=True, required=False)
|
||||||
|
remark = serializers.CharField(required=False, label='操作备注')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,11 +3,16 @@ from rest_framework import urlpatterns
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
from apps.wpm.views import WMaterialViewSet
|
from apps.wpm.views import DoFormInit, DoFormSubmit, OperationViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet
|
||||||
|
|
||||||
router = DefaultRouter()
|
router = DefaultRouter()
|
||||||
router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
|
router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
|
||||||
|
router.register('wproduct', WProductViewSet, basename='wproduct')
|
||||||
|
router.register('operation', OperationViewSet, basename='operation')
|
||||||
|
router.register('subplan', WPlanViewSet, basename='wplan')
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
|
path('do/init/', DoFormInit.as_view()),
|
||||||
|
path('do/submit/', DoFormSubmit.as_view()),
|
||||||
path('', include(router.urls)),
|
path('', include(router.urls)),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,17 +1,35 @@
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from rest_framework.generics import CreateAPIView, GenericAPIView
|
from rest_framework.generics import CreateAPIView, GenericAPIView
|
||||||
from rest_framework.mixins import ListModelMixin
|
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
|
||||||
|
from rest_framework.utils import serializer_helpers
|
||||||
from rest_framework.utils.field_mapping import get_relation_kwargs
|
from rest_framework.utils.field_mapping import get_relation_kwargs
|
||||||
|
from rest_framework.views import APIView
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||||
from apps.pm.serializers import SubProductionPlanUpdateSerializer
|
from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial
|
||||||
|
from apps.mtm.serializers import RecordFormDetailSerializer
|
||||||
|
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
||||||
|
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer
|
||||||
|
|
||||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from apps.wpm.models import WMaterial
|
from apps.wpm.models import WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
|
||||||
|
|
||||||
from apps.wpm.serializers import PickSerializer, WMaterialListSerializer
|
from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
|
from django.db import transaction
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
|
"""
|
||||||
|
车间生产计划
|
||||||
|
"""
|
||||||
|
perms_map = {'*': '*'}
|
||||||
|
queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'main_product').exclude(state=0)
|
||||||
|
search_fields = []
|
||||||
|
serializer_class = SubProductionPlanListSerializer
|
||||||
|
filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop']
|
||||||
|
ordering_fields = ['process__number']
|
||||||
|
ordering = ['process__number']
|
||||||
|
|
||||||
class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
|
class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
车间物料表
|
车间物料表
|
||||||
|
@ -19,7 +37,7 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
|
||||||
perms_map={'*':'*'}
|
perms_map={'*':'*'}
|
||||||
queryset = WMaterial.objects.select_related('material').all()
|
queryset = WMaterial.objects.select_related('material').all()
|
||||||
serializer_class = WMaterialListSerializer
|
serializer_class = WMaterialListSerializer
|
||||||
filterset_fields = ['material', 'process', 'workshop']
|
filterset_fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop']
|
||||||
ordering_fields = ['material__number']
|
ordering_fields = ['material__number']
|
||||||
ordering = ['material__number']
|
ordering = ['material__number']
|
||||||
|
|
||||||
|
@ -33,8 +51,209 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
|
||||||
serializer.save()
|
serializer.save()
|
||||||
return Response()
|
return Response()
|
||||||
|
|
||||||
class DoFormInit(CreateAPIView):
|
class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
生产操作表单创建
|
半成品
|
||||||
"""
|
"""
|
||||||
perms_map={'*':'*'}
|
perms_map={'*':'*'}
|
||||||
|
queryset = WProduct.objects.select_related('p_state', 'm_state').filter(is_hidden=False)
|
||||||
|
serializer_class = WProductListSerializer
|
||||||
|
filterset_fields = ['p_state', 'subproduction_plan', 'm_state', 'production_plan', 'p_state__process']
|
||||||
|
search_fields = ['number']
|
||||||
|
ordering_fields = ['id']
|
||||||
|
ordering = ['id']
|
||||||
|
|
||||||
|
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PickSerializer)
|
||||||
|
def test():
|
||||||
|
pass
|
||||||
|
|
||||||
|
class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||||
|
"""
|
||||||
|
生产操作记录
|
||||||
|
"""
|
||||||
|
perms_map={'*':'*'}
|
||||||
|
queryset = Operation.objects.select_related('p_state', 'm_state').all()
|
||||||
|
serializer_class = OperationListSerializer
|
||||||
|
filterset_fields = ['p_state', 'm_state']
|
||||||
|
ordering_fields = ['id']
|
||||||
|
ordering = ['-id']
|
||||||
|
|
||||||
|
def get_serializer_class(self):
|
||||||
|
if self.action == 'retrieve':
|
||||||
|
return OperationDetailSerializer
|
||||||
|
return super().get_serializer_class()
|
||||||
|
|
||||||
|
class DoFormInit(CreateAPIView, GenericAPIView):
|
||||||
|
perms_map={'*':'*'}
|
||||||
|
serializer_class=OperationInitSerializer
|
||||||
|
def post(self, request, format=None):
|
||||||
|
"""
|
||||||
|
调用操作表单
|
||||||
|
"""
|
||||||
|
data = request.data
|
||||||
|
serializer = OperationInitSerializer(data=data)
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.validated_data
|
||||||
|
ret = {}
|
||||||
|
ret_0 = {}
|
||||||
|
ret_0['step'] = data['step']
|
||||||
|
ret_0['subproduction_plan'] = data['subproduction_plan']
|
||||||
|
if 'wproducts' in data and data['wproducts']:
|
||||||
|
ret_0['wproducts'] = data['wproducts']
|
||||||
|
else:
|
||||||
|
ret_0['wproducts'] = []
|
||||||
|
# 调出该子计划现有物料
|
||||||
|
ret_0['input'] = list(WMaterial.objects.filter(subproduction_plan=vdata['subproduction_plan'])\
|
||||||
|
.values('id', 'material', 'material__name', 'count', 'material__number', 'batch'))
|
||||||
|
for i in ret_0['input']:
|
||||||
|
i['count_input'] = 0
|
||||||
|
# 需要输出的物料
|
||||||
|
if ret_0['wproducts']:
|
||||||
|
# 排除主要产物, 因为已经放到半成品里了, 由半成品进行处理, 夹层可能需要特殊处理
|
||||||
|
o_objs = SubProductionProgress.objects.filter(
|
||||||
|
subproduction_plan=vdata['subproduction_plan'], type=SubprodctionMaterial.SUB_MA_TYPE_OUT).exclude(is_main=True)
|
||||||
|
|
||||||
|
else:
|
||||||
|
o_objs = SubProductionProgress.objects.filter(
|
||||||
|
subproduction_plan=vdata['subproduction_plan'], type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
||||||
|
ret_0['output'] = list(o_objs.values('material', 'material__name', 'material__number'))
|
||||||
|
for i in ret_0['output']:
|
||||||
|
i['count_output']=0
|
||||||
|
ret['forms'] = []
|
||||||
|
ret_0['id'] = 0
|
||||||
|
ret_0['name'] = '基本信息'
|
||||||
|
ret['forms'].append(ret_0)
|
||||||
|
forms = RecordForm.objects.filter(step=vdata['step'], type=RecordForm.RF_TYPE_DO)
|
||||||
|
if forms.exists():
|
||||||
|
ret['forms'].extend(RecordFormDetailSerializer(instance=forms, many=True).data)
|
||||||
|
return Response(ret)
|
||||||
|
|
||||||
|
|
||||||
|
class DoFormSubmit(CreateAPIView, GenericAPIView):
|
||||||
|
perms_map={'*':'*'}
|
||||||
|
serializer_class = OperationSubmitSerializer
|
||||||
|
|
||||||
|
@transaction.atomic
|
||||||
|
def post(self, request, format=None):
|
||||||
|
"""
|
||||||
|
提交操作表单
|
||||||
|
"""
|
||||||
|
data = request.data
|
||||||
|
serializer = OperationSubmitSerializer(data=data, context={'request':self.request})
|
||||||
|
serializer.is_valid(raise_exception=True)
|
||||||
|
vdata = serializer.validated_data #校验之后的数据
|
||||||
|
|
||||||
|
# 创建一个生产操作记录
|
||||||
|
action_obj = Operation()
|
||||||
|
action_obj.p_state = vdata['step']
|
||||||
|
if 'wproducts' in data and data['wproducts']:
|
||||||
|
action_obj.wproducts = data['wproducts']
|
||||||
|
action_obj.m_state = vdata['wproducts'][0].m_state
|
||||||
|
action_obj.remark = vdata.get('remark', '') # 操作备注
|
||||||
|
action_obj.create_by = request.user
|
||||||
|
action_obj.save()
|
||||||
|
|
||||||
|
# 保存物料消耗
|
||||||
|
for i in vdata['input']:
|
||||||
|
if i['count_input']: #如果有消耗
|
||||||
|
i_wmat = i['id']
|
||||||
|
OperationMaterial.objects.create(type=1, operation=action_obj,
|
||||||
|
wmaterial= i_wmat, count=i['count_input'])
|
||||||
|
# 更新车间物料
|
||||||
|
i_wmat.count = i_wmat.count- i['count_input']
|
||||||
|
i_wmat.save()
|
||||||
|
# 更新子计划物料消耗情况
|
||||||
|
sp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan,
|
||||||
|
material=i_wmat.material)
|
||||||
|
sp.count_real = sp.count_real + i['count_input']
|
||||||
|
sp.save()
|
||||||
|
|
||||||
|
# 物料产出
|
||||||
|
if 'output' in data and data['output']:
|
||||||
|
for i in vdata['output']: # 已经序列化好的数据
|
||||||
|
ma = i['material']
|
||||||
|
if vdata['subproduction_plan'].main_product == ma: # 如果是该计划主产物
|
||||||
|
# 如果是切割
|
||||||
|
# 获取下一步子工序
|
||||||
|
if vdata['step'].type == Step.STEP_TYPE_DIV:
|
||||||
|
stepIds = [i['id'] for i in vdata['subproduction_plan'].steps]
|
||||||
|
pindex = stepIds.index(vdata['step'].id)
|
||||||
|
wpr = dict(m_state=ma, p_state=Step.objects.get(pk=stepIds[pindex+1]),
|
||||||
|
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
|
||||||
|
subproduction_plan=vdata['subproduction_plan'],
|
||||||
|
production_plan=vdata['subproduction_plan'].production_plan)
|
||||||
|
for x in range(i['count_output']):
|
||||||
|
WProduct.objects.create(**wpr)
|
||||||
|
else:
|
||||||
|
# 更新操作产出物料表
|
||||||
|
OperationMaterial.objects.create(type=2, operation=action_obj,
|
||||||
|
material= ma, count=i['count_output'])
|
||||||
|
# 更新车间物料表
|
||||||
|
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=vdata['subproduction_plan'],
|
||||||
|
material=ma)
|
||||||
|
ins.count = ins.count + i['count_output']
|
||||||
|
ins.save()
|
||||||
|
# 更新子计划进度表
|
||||||
|
sp = SubProductionProgress.objects.get(subproduction_plan=vdata['subproduction_plan'],
|
||||||
|
material=ma)
|
||||||
|
sp.count_real = sp.count_real + i['count_input']
|
||||||
|
sp.save()
|
||||||
|
|
||||||
|
# 更新动态产品表
|
||||||
|
if 'wproducts' in data and data['wproducts']:
|
||||||
|
wproducts = WProduct.objects.filter(pk__in=data['wproducts'])
|
||||||
|
# 获取下一步子工序
|
||||||
|
stepIds = [i['id'] for i in vdata['subproduction_plan'].steps]
|
||||||
|
pindex = stepIds.index(vdata['step'].id)
|
||||||
|
if pindex + 1 < len(stepIds): # 如果不是最后一步
|
||||||
|
newstep = Step.objects.get(pk=stepIds[pindex+1])
|
||||||
|
wproducts.update(p_state=newstep, is_executed=False)
|
||||||
|
|
||||||
|
# 特殊情况如果是夹层结合
|
||||||
|
if vdata['step'].type == Step.STEP_TYPE_COMB:
|
||||||
|
wproducts.update(is_hidden=True) # 隐藏
|
||||||
|
|
||||||
|
WProduct.objects.create(
|
||||||
|
m_state=vdata['subproduction_plan'].main_product, p_state = newstep,
|
||||||
|
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
|
||||||
|
subproduction_plan=vdata['subproduction_plan'],
|
||||||
|
production_plan=vdata['subproduction_plan'].production_plan,
|
||||||
|
parent = data['wproducts']
|
||||||
|
)
|
||||||
|
|
||||||
|
else: # 如果是最后一步, 此时需要转序并更新状态为待检测
|
||||||
|
newstep = vdata['step']
|
||||||
|
wproducts.update(p_state=newstep, is_executed=True, act_state=WProduct.WPR_ACT_STATE_TOTEST)
|
||||||
|
|
||||||
|
# 特殊情况如果是夹层结合
|
||||||
|
if vdata['step'].type == Step.STEP_TYPE_COMB:
|
||||||
|
wproducts.update(is_hidden=True) # 隐藏
|
||||||
|
|
||||||
|
WProduct.objects.create(
|
||||||
|
m_state=vdata['subproduction_plan'].main_product, p_state = newstep,
|
||||||
|
act_state=WProduct.WPR_ACT_STATE_TOTEST, is_executed=True, remark='',
|
||||||
|
subproduction_plan=vdata['subproduction_plan'],
|
||||||
|
production_plan=vdata['subproduction_plan'].production_plan
|
||||||
|
)
|
||||||
|
|
||||||
|
# 保存自定义表单结果
|
||||||
|
for i in vdata['forms']:
|
||||||
|
wr = OperationRecord()
|
||||||
|
wr.form = i['form']
|
||||||
|
wr.create_by = request.user
|
||||||
|
wr.operation = action_obj
|
||||||
|
wr.save()
|
||||||
|
wrds = []
|
||||||
|
for m in i['record_data']: # 保存记录详情
|
||||||
|
form_field = m['form_field']
|
||||||
|
m['field_name'] = form_field.field_name
|
||||||
|
m['field_key'] = form_field.field_key
|
||||||
|
m['field_type'] = form_field.field_type
|
||||||
|
m['field_value'] = m['field_value']
|
||||||
|
m['sort'] = form_field.sort
|
||||||
|
m['operation_record'] = wr
|
||||||
|
wrds.append(OperationRecordItem(**m))
|
||||||
|
OperationRecordItem.objects.bulk_create(wrds)
|
||||||
|
return Response()
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,8 @@ from django.db import models
|
||||||
import django.utils.timezone as timezone
|
import django.utils.timezone as timezone
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
|
||||||
|
|
||||||
# 自定义软删除查询基类
|
# 自定义软删除查询基类
|
||||||
|
|
||||||
|
|
||||||
class SoftDeletableQuerySetMixin(object):
|
class SoftDeletableQuerySetMixin(object):
|
||||||
'''
|
'''
|
||||||
QuerySet for SoftDeletableModel. Instead of removing instance sets
|
QuerySet for SoftDeletableModel. Instead of removing instance sets
|
||||||
|
@ -63,6 +62,24 @@ class BaseModel(models.Model):
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if self.pk:
|
||||||
|
# If self.pk is not None then it's an update.
|
||||||
|
cls = self.__class__
|
||||||
|
old = cls.objects.get(pk=self.pk)
|
||||||
|
# This will get the current model state since super().save() isn't called yet.
|
||||||
|
new = self # This gets the newly instantiated Mode object with the new values.
|
||||||
|
changed_fields = []
|
||||||
|
for field in cls._meta.get_fields():
|
||||||
|
field_name = field.name
|
||||||
|
try:
|
||||||
|
if getattr(old, field_name) != getattr(new, field_name):
|
||||||
|
changed_fields.append(field_name)
|
||||||
|
except Exception as ex: # Catch field does not exist exception
|
||||||
|
pass
|
||||||
|
kwargs['update_fields'] = changed_fields
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
class SoftModel(BaseModel):
|
class SoftModel(BaseModel):
|
||||||
"""
|
"""
|
||||||
软删除基本表
|
软删除基本表
|
||||||
|
|
Loading…
Reference in New Issue