Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
f63bb65a9e
|
@ -122,4 +122,4 @@ body .el-table th.gutter{
|
|||
}
|
||||
.el-dialog__footer{
|
||||
padding: 6px 6px 6px;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
# Generated by Django 3.2.6 on 2021-11-11 01:18
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('inm', '0013_alter_materialbatch_batch'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='fifo',
|
||||
name='warehouse',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='fifoitem',
|
||||
name='warehouse',
|
||||
field=models.ForeignKey(default=2, on_delete=django.db.models.deletion.CASCADE, to='inm.warehouse', verbose_name='仓库'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='fifoitem',
|
||||
name='count',
|
||||
field=models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)], verbose_name='数量'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='inventory',
|
||||
name='count',
|
||||
field=models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)], verbose_name='仓库物料存量'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='materialbatch',
|
||||
name='count',
|
||||
field=models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)], verbose_name='存量'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.2.6 on 2021-11-11 01:40
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('inm', '0014_auto_20211111_0918'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='fifo',
|
||||
name='operator',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='fifo',
|
||||
name='auditor',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='审核人'),
|
||||
),
|
||||
]
|
|
@ -7,6 +7,7 @@ from utils.model import SoftModel, BaseModel
|
|||
from simple_history.models import HistoricalRecords
|
||||
from apps.mtm.models import Material
|
||||
from apps.pm.models import SubProductionPlan
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
|
||||
|
||||
class WareHouse(CommonAModel):
|
||||
|
@ -28,7 +29,7 @@ class Inventory(BaseModel):
|
|||
库存物料
|
||||
"""
|
||||
material = models.ForeignKey(Material, on_delete=models.CASCADE, verbose_name='物料信息')
|
||||
count = models.IntegerField('仓库物料存量', default=0)
|
||||
count = models.IntegerField('仓库物料存量', default=0, validators=[MinValueValidator(0)])
|
||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||
class Meta:
|
||||
verbose_name = '库存表'
|
||||
|
@ -40,7 +41,7 @@ class MaterialBatch(BaseModel):
|
|||
"""
|
||||
material = models.ForeignKey(Material, on_delete=models.CASCADE, verbose_name='物料信息')
|
||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||
count = models.IntegerField('存量', default=0)
|
||||
count = models.IntegerField('存量', default=0, validators=[MinValueValidator(0)])
|
||||
batch = models.CharField('批次号', max_length=100, default='')
|
||||
expiration_date = models.DateField('有效期', null=True, blank=True)
|
||||
class Meta:
|
||||
|
@ -65,8 +66,7 @@ class FIFO(CommonAModel):
|
|||
)
|
||||
type = models.IntegerField('出入库类型', default=1)
|
||||
is_audited = models.BooleanField('是否审核', default=False)
|
||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='仓库')
|
||||
operator = models.ForeignKey(User, verbose_name='操作人', on_delete=models.CASCADE)
|
||||
auditor = models.ForeignKey(User, verbose_name='审核人', on_delete=models.CASCADE, null=True, blank=True)
|
||||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.DO_NOTHING, null=True, blank=True)
|
||||
inout_date = models.DateField('出入库日期')
|
||||
remark = models.CharField('备注', max_length=1000, default='')
|
||||
|
@ -78,8 +78,9 @@ class FIFOItem(BaseModel):
|
|||
"""
|
||||
is_tested = models.BooleanField('是否已检测', default=False)
|
||||
is_testok = models.BooleanField('是否检测合格', default=False)
|
||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='仓库')
|
||||
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||
count = models.IntegerField('数量', default=0)
|
||||
count = models.IntegerField('数量', default=0, validators=[MinValueValidator(0)])
|
||||
batch = models.CharField('批次号', max_length=100, default='')
|
||||
fifo = models.ForeignKey(FIFO, verbose_name='关联出入库', on_delete=models.CASCADE)
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory
|
||||
from apps.qm.models import TestRecord, TestRecordItem
|
||||
|
||||
from apps.system.serializers import UserSimpleSerializer
|
||||
from apps.mtm.serializers import MaterialSimpleSerializer
|
||||
|
@ -37,13 +38,14 @@ class MaterialBatchSerializer(serializers. ModelSerializer):
|
|||
fields = '__all__'
|
||||
|
||||
class FIFOListSerializer(serializers.ModelSerializer):
|
||||
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
||||
operator_ = UserSimpleSerializer(source='operator', read_only=True)
|
||||
auditor_ = UserSimpleSerializer(source='auditor', read_only=True)
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
class Meta:
|
||||
model=FIFO
|
||||
fields = '__all__'
|
||||
|
||||
class FIFOItemSerializer(serializers.ModelSerializer):
|
||||
warehouse_ = WareHouseSimpleSerializer(source='warehouse', read_only=True)
|
||||
material_= MaterialSimpleSerializer(source='material', read_only=True)
|
||||
class Meta:
|
||||
model= FIFOItem
|
||||
|
@ -58,7 +60,7 @@ class FIFODetailInPurSerializer(serializers.ModelSerializer):
|
|||
details = IProductInPurSerializer(many=True, required=False)
|
||||
class Meta:
|
||||
model = FIFOItem
|
||||
fields = ['material', 'count', 'batch', 'details']
|
||||
fields = ['material', 'count', 'batch', 'details', 'warehouse']
|
||||
|
||||
class MaterialBatchQuerySerializer(serializers.Serializer):
|
||||
warehouse = serializers.IntegerField(label="仓库ID", required=False)
|
||||
|
@ -72,7 +74,7 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
|||
details = FIFODetailInPurSerializer(many=True)
|
||||
class Meta:
|
||||
model = FIFO
|
||||
fields = ['warehouse', 'operator', 'details', 'inout_date']
|
||||
fields = ['details', 'inout_date']
|
||||
|
||||
def create(self, validated_data):
|
||||
details = validated_data.pop('details')
|
||||
|
@ -80,16 +82,16 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
|||
pass
|
||||
else:
|
||||
raise serializers.ValidationError('没有入库内容')
|
||||
|
||||
for i in details:
|
||||
# 校验批次
|
||||
try:
|
||||
if i['batch']:
|
||||
obj = MaterialBatch.objects.get(batch=i['batch'], material=i['material'])
|
||||
if obj.warehouse != validated_data['warehouse']:
|
||||
raise serializers.ValidationError('批次号{}在其他仓库已存在'.format(i['batch']))
|
||||
except:
|
||||
pass
|
||||
|
||||
# for i in details:
|
||||
# # 校验批次
|
||||
# try:
|
||||
# if i['batch']:
|
||||
# obj = MaterialBatch.objects.get(batch=i['batch'], material=i['material'])
|
||||
# if obj.warehouse != validated_data['warehouse']:
|
||||
# raise serializers.ValidationError('批次号{}在其他仓库已存在'.format(i['batch']))
|
||||
# except:
|
||||
# pass
|
||||
|
||||
# 创建采购入库
|
||||
with transaction.atomic():
|
||||
|
@ -118,3 +120,16 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
|||
FIFOItem.objects.create(**i)
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
class InmTestRecordItemCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = TestRecordItem
|
||||
fields = ['form_field', 'field_value', 'is_testok']
|
||||
|
||||
class InmTestRecordCreateSerializer(serializers.ModelSerializer):
|
||||
record_data = InmTestRecordItemCreateSerializer(many=True)
|
||||
fifo_item = serializers.PrimaryKeyRelatedField(queryset=FIFOItem.objects.all(), required=True)
|
||||
class Meta:
|
||||
model = TestRecord
|
||||
fields = ['form', 'record_data', 'is_testok', 'fifo_item']
|
|
@ -8,11 +8,11 @@ def update_inm(instance:FIFO, type:int=1):
|
|||
"""
|
||||
更新库存(正反)
|
||||
"""
|
||||
warehouse = instance.warehouse
|
||||
if instance.type in [FIFO.FIFO_TYPE_PUR_IN]: # 采购入库
|
||||
# 更新相关表
|
||||
for i in FIFOItem.objects.filter(fifo=instance):
|
||||
material = i.material
|
||||
warehouse = i.warehouse
|
||||
o1, _ = Inventory.objects.get_or_create(material=material, warehouse=warehouse, \
|
||||
defaults={'material':material, 'warehouse':warehouse, 'count':0})
|
||||
o1.count = o1.count + i.count
|
||||
|
@ -27,6 +27,7 @@ def update_inm(instance:FIFO, type:int=1):
|
|||
# 更新相关表
|
||||
for i in FIFOItem.objects.filter(fifo=instance):
|
||||
material = i.material
|
||||
warehouse = i.warehouse
|
||||
o1 = Inventory.objects.get(material=material, warehouse=warehouse)
|
||||
o1.count = o1.count - i.count
|
||||
o1.save()
|
||||
|
|
|
@ -9,7 +9,7 @@ router.register('warehouse', WarehouseViewSet, basename='warehouse')
|
|||
router.register('inventory', InventoryViewSet, basename='inventory')
|
||||
router.register('materialbatch', MaterialBatchViewSet, basename='materialbatch')
|
||||
router.register('fifo', FIFOViewSet, basename='fifo'),
|
||||
router.register('fifodetail', FIFOItemViewSet, basename='fifodetail')
|
||||
router.register('fifoitem', FIFOItemViewSet, basename='fifoitem')
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
|
|
|
@ -6,8 +6,9 @@ from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
|||
from apps.inm.filters import MbFilterSet
|
||||
|
||||
from apps.inm.models import FIFO, FIFOItem, MaterialBatch, WareHouse,Inventory
|
||||
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
|
||||
from apps.inm.serializers import FIFOItemSerializer, FIFOInPurSerializer, FIFOListSerializer, InmTestRecordCreateSerializer, MaterialBatchQuerySerializer, MaterialBatchSerializer, WareHouseSerializer, WareHouseCreateUpdateSerializer,InventorySerializer
|
||||
from apps.inm.signals import update_inm
|
||||
from apps.qm.models import TestRecordItem
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.response import Response
|
||||
|
@ -81,16 +82,50 @@ class FIFOItemViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
|
|||
raise APIException('该出入库记录已通过审核, 无法删除')
|
||||
return super().perform_destroy(instance)
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=InmTestRecordCreateSerializer)
|
||||
def test(self, request, pk=None):
|
||||
"""
|
||||
检测
|
||||
"""
|
||||
serializer = InmTestRecordCreateSerializer(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)
|
||||
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_item:
|
||||
obj.fifo_item.is_testok = True if obj.is_testok else False
|
||||
obj.fifo_item.is_tested = True
|
||||
obj.fifo_item.save()
|
||||
return Response()
|
||||
|
||||
class FIFOViewSet(ListModelMixin, GenericViewSet):
|
||||
"""
|
||||
出入库记录
|
||||
"""
|
||||
perms_map = {'*': '*'}
|
||||
queryset = FIFO.objects.select_related('warehouse', 'operator')
|
||||
queryset = FIFO.objects.select_related('auditor', 'create_by')
|
||||
serializer_class = FIFOListSerializer
|
||||
filterset_fields = '__all__'
|
||||
ordering_fields = '__all__'
|
||||
search_fields = ['warehouse__name', 'warehouse__number']
|
||||
search_fields = []
|
||||
ordering = ['-pk']
|
||||
|
||||
def get_serializer_class(self):
|
||||
|
@ -121,6 +156,7 @@ class FIFOViewSet(ListModelMixin, GenericViewSet):
|
|||
raise APIException('该入库记录已审核通过')
|
||||
with transaction.atomic():
|
||||
obj.is_audited = True
|
||||
obj.auditor = request.user
|
||||
obj.save()
|
||||
update_inm(obj) # 更新库存
|
||||
return Response()
|
||||
|
|
|
@ -171,7 +171,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
|
|||
materials = []
|
||||
for i in need:
|
||||
materials.append(i['material'])
|
||||
objs = MaterialBatch.objects.filter(warehouse=request.data['warehouse'], material__id__in=materials)
|
||||
objs = MaterialBatch.objects.filter(material__id__in=materials)
|
||||
have = MaterialBatchSerializer(instance=objs, many=True).data
|
||||
return Response({'need':need, 'have':have})
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 3.2.6 on 2021-11-11 06:05
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0029_step_type'),
|
||||
('wpm', '0012_auto_20211111_1056'),
|
||||
('qm', '0007_alter_testrecorditem_field_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='testrecord',
|
||||
name='m_state',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='关联的物料状态'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='testrecord',
|
||||
name='remark',
|
||||
field=models.TextField(default='', verbose_name='备注'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='testrecord',
|
||||
name='wproduct',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='关联的动态产品'),
|
||||
),
|
||||
]
|
|
@ -49,7 +49,10 @@ class TestRecord(CommonAModel):
|
|||
"""
|
||||
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
|
||||
is_testok = models.BooleanField('是否合格', default=True)
|
||||
wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True)
|
||||
m_state = models.ForeignKey('mtm.material', 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)
|
||||
remark = models.TextField('备注', default='')
|
||||
|
||||
|
||||
class TestRecordItem(BaseModel):
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
|
||||
from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer, TestRecordCreateSerializer, TestRecordDetailSerializer, TestRecordListSerializer
|
||||
from apps.qm.models import Standard, TestItem, TestRecord, TestRecordItem
|
||||
from django.shortcuts import render
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
||||
from apps.system.mixins import CreateUpdateModelAMixin
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework.response import Response
|
||||
|
@ -42,7 +43,7 @@ class TestItemViewSet(CreateUpdateModelAMixin, ModelViewSet):
|
|||
return TestItemCreateUpdateSerializer
|
||||
return TestItemSerializer
|
||||
|
||||
class TestRecordViewSet(ModelViewSet):
|
||||
class TestRecordViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||
"""
|
||||
检测记录
|
||||
"""
|
||||
|
@ -52,41 +53,39 @@ class TestRecordViewSet(ModelViewSet):
|
|||
ordering = ['-id']
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == 'create':
|
||||
return TestRecordCreateSerializer
|
||||
elif self.action == 'list':
|
||||
if self.action == 'list':
|
||||
return TestRecordListSerializer
|
||||
elif self.action == 'retrieve':
|
||||
return TestRecordDetailSerializer
|
||||
return super().get_serializer_class()
|
||||
|
||||
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)
|
||||
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)
|
||||
# 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)
|
||||
# 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_item:
|
||||
obj.fifo_item.is_testok = True if obj.is_testok else False
|
||||
obj.fifo_item.is_tested = True
|
||||
obj.fifo_item.save()
|
||||
# # 如果检测合格
|
||||
# if obj.fifo_item:
|
||||
# obj.fifo_item.is_testok = True if obj.is_testok else False
|
||||
# obj.fifo_item.is_tested = True
|
||||
# obj.fifo_item.save()
|
||||
|
||||
return Response(status=status.HTTP_201_CREATED)
|
||||
# return Response(status=status.HTTP_201_CREATED)
|
|
@ -0,0 +1,41 @@
|
|||
# Generated by Django 3.2.6 on 2021-11-11 02:56
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mtm', '0029_step_type'),
|
||||
('wpm', '0011_alter_operationrecorditem_operation_record'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='operation',
|
||||
name='use_scrap',
|
||||
field=models.BooleanField(default=False, verbose_name='是否使用的边角料'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='wproduct',
|
||||
name='pre_pstate',
|
||||
field=models.ForeignKey(blank=True, help_text='已执行完的步骤', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='w_pre_pstate', to='mtm.step', verbose_name='已执行到'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='operationmaterial',
|
||||
name='count',
|
||||
field=models.IntegerField(validators=[django.core.validators.MinValueValidator(0)], verbose_name='消耗或产出数量'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wmaterial',
|
||||
name='count',
|
||||
field=models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)], verbose_name='当前数量'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='wproduct',
|
||||
name='p_state',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='w_ptate', to='mtm.step', verbose_name='所在步骤'),
|
||||
),
|
||||
]
|
|
@ -7,7 +7,7 @@ from apps.system.models import CommonAModel, CommonBModel, Organization, User, D
|
|||
from utils.model import SoftModel, BaseModel
|
||||
from simple_history.models import HistoricalRecords
|
||||
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm
|
||||
|
||||
from django.core.validators import MinValueValidator
|
||||
class WMaterial(BaseModel):
|
||||
"""
|
||||
车间生产物料
|
||||
|
@ -15,7 +15,7 @@ class WMaterial(BaseModel):
|
|||
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子计划', on_delete=models.CASCADE)
|
||||
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
|
||||
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
|
||||
count = models.IntegerField('当前数量', default=0)
|
||||
count = models.IntegerField('当前数量', default=0, validators=[MinValueValidator(0)])
|
||||
|
||||
class WProduct(CommonAModel):
|
||||
"""
|
||||
|
@ -31,7 +31,8 @@ class WProduct(CommonAModel):
|
|||
)
|
||||
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
|
||||
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)
|
||||
pre_pstate = models.ForeignKey(Step, verbose_name='已执行到', help_text='已执行完的步骤', null=True, blank=True, on_delete=models.CASCADE, related_name='w_pre_pstate')
|
||||
p_state = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True, related_name='w_ptate')
|
||||
act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices)
|
||||
is_executed = models.BooleanField('子工序是否已执行', default=False)
|
||||
is_hidden = models.BooleanField('是否隐藏', default=False)
|
||||
|
@ -48,11 +49,12 @@ 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)
|
||||
use_scrap = models.BooleanField('是否使用的边角料', default=False)
|
||||
remark = models.CharField('操作备注', max_length=200, null=True, blank=True)
|
||||
|
||||
class OperationMaterial(BaseModel):
|
||||
"""
|
||||
车间生产物料消耗产出表
|
||||
生产操作物料消耗产出表
|
||||
"""
|
||||
type_choices=(
|
||||
(1, '消耗'),
|
||||
|
@ -62,7 +64,7 @@ class OperationMaterial(BaseModel):
|
|||
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('消耗或产出数量')
|
||||
count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)])
|
||||
|
||||
class OperationRecord(CommonAModel):
|
||||
"""
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from rest_framework import serializers
|
||||
from rest_framework import serializers, exceptions
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from apps.inm.models import FIFO, FIFOItem, MaterialBatch, WareHouse
|
||||
from apps.inm.signals import update_inm
|
||||
|
@ -8,6 +8,7 @@ from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer
|
|||
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from apps.qm.models import TestRecord, TestRecordItem
|
||||
from apps.system.serializers import UserSimpleSerializer
|
||||
from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, OperationRecordItem
|
||||
from django.db import transaction
|
||||
|
@ -15,32 +16,30 @@ from django.db import transaction
|
|||
class PickDetailSerializer(serializers.Serializer):
|
||||
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
|
||||
batch = serializers.CharField(label='物料批次', allow_blank=True)
|
||||
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
|
||||
pick_count = serializers.IntegerField(label="领料数量")
|
||||
|
||||
class PickSerializer(serializers.Serializer):
|
||||
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
|
||||
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
|
||||
picks = PickDetailSerializer(many=True)
|
||||
|
||||
def create(self, validated_data):
|
||||
picks = validated_data.pop('picks')
|
||||
sp = validated_data['subproduction_plan']
|
||||
if sp.state not in [1,2]:
|
||||
raise serializers.ValidationError('该子计划状态错误')
|
||||
raise exceptions.ValidationError('该子计划状态错误')
|
||||
if sp.is_picked:
|
||||
raise serializers.ValidationError('该子计划已领料')
|
||||
for i in picks:
|
||||
try:
|
||||
instance = MaterialBatch.objects.get(material=i['material'], batch=i['batch'])
|
||||
if instance.count < i['pick_count']:
|
||||
raise serializers.ValidationError('物料不足')
|
||||
except:
|
||||
raise serializers.ValidationError('物料不存在')
|
||||
raise exceptions.ValidationError('该子计划已领料')
|
||||
# for i in picks:
|
||||
# try:
|
||||
# instance = MaterialBatch.objects.get(material=i['material'], batch=i['batch'])
|
||||
# if instance.count < i['pick_count']:
|
||||
# raise exceptions.ValidationError('物料不足')
|
||||
# except:
|
||||
# raise exceptions.ValidationError('物料不存在')
|
||||
# 创建出库记录
|
||||
with transaction.atomic():
|
||||
operator = self.context['request'].user
|
||||
validated_data['create_by'] = operator
|
||||
validated_data['operator'] = operator
|
||||
validated_data['create_by'] = self.context['request'].user
|
||||
validated_data['type'] = FIFO.FIFO_TYPE_DO_OUT
|
||||
validated_data['inout_date'] = timezone.now()
|
||||
fifo = FIFO.objects.create(**validated_data)
|
||||
|
@ -126,21 +125,21 @@ class OperationInitSerializer(serializers.Serializer):
|
|||
|
||||
stepIds=[i['id'] for i in subproduction_plan.steps]
|
||||
if step.id not in stepIds:
|
||||
raise serializers.ValidationError('请选择正确的子工序操作')
|
||||
raise exceptions.ValidationError('请选择正确的子工序操作')
|
||||
|
||||
if 'wproducts' in data and data['wproducts']:
|
||||
if step.type == Step.STEP_TYPE_DIV:
|
||||
raise serializers.ValidationError(_('不可进行此操作'))
|
||||
raise exceptions.ValidationError(_('不可进行此操作'))
|
||||
for i in data['wproducts']:
|
||||
if i.is_executed:
|
||||
raise serializers.ValidationError('不可进行操作')
|
||||
raise exceptions.ValidationError('不可进行操作')
|
||||
if i.subproduction_plan != subproduction_plan:
|
||||
raise serializers.ValidationError('半成品所属子计划不一致')
|
||||
raise exceptions.ValidationError('半成品所属子计划不一致')
|
||||
if i.p_state != step:
|
||||
raise serializers.ValidationError('半成品所属子工序不一致')
|
||||
raise exceptions.ValidationError('半成品所属子工序不一致')
|
||||
else:
|
||||
if step.type != Step.STEP_TYPE_DIV:
|
||||
raise serializers.ValidationError(_('请选择半成品进行操作'))
|
||||
raise exceptions.ValidationError(_('请选择半成品进行操作'))
|
||||
return data
|
||||
|
||||
|
||||
|
@ -174,6 +173,19 @@ class OperationSubmitSerializer(serializers.Serializer):
|
|||
output = DoOutputSerializer(many=True, required=False)
|
||||
forms = OperationRecordSerializer(many=True, required=False)
|
||||
remark = serializers.CharField(required=False, label='操作备注', allow_blank=True, allow_null=True)
|
||||
use_scrap = serializers.BooleanField(required=False, default=False)
|
||||
|
||||
class WpmTestRecordItemCreateSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = TestRecordItem
|
||||
fields = ['form_field', 'field_value', 'is_testok']
|
||||
|
||||
class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
|
||||
record_data = WpmTestRecordItemCreateSerializer(many=True)
|
||||
wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
|
||||
class Meta:
|
||||
model = TestRecord
|
||||
fields = ['form', 'record_data', 'is_testok', 'wproduct']
|
||||
|
||||
|
||||
|
|
@ -9,14 +9,16 @@ 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.qm.models import TestRecordItem
|
||||
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
from rest_framework.decorators import action
|
||||
from apps.wpm.models import WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
|
||||
|
||||
from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer
|
||||
from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WpmTestRecordCreateSerializer
|
||||
from rest_framework.response import Response
|
||||
from django.db import transaction
|
||||
from rest_framework import exceptions
|
||||
# Create your views here.
|
||||
class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||
"""
|
||||
|
@ -63,9 +65,40 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
|||
ordering_fields = ['id']
|
||||
ordering = ['id']
|
||||
|
||||
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PickSerializer)
|
||||
def test():
|
||||
pass
|
||||
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=WpmTestRecordCreateSerializer)
|
||||
@transaction.atomic
|
||||
def test(self, request, pk=None):
|
||||
"""
|
||||
检测
|
||||
"""
|
||||
serializer = WpmTestRecordCreateSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
vdata = serializer.validated_data
|
||||
record_data = vdata.pop('record_data')
|
||||
wproduct = vdata['wproduct']
|
||||
if wproduct.act_state != WProduct.WPR_ACT_STATE_TOTEST:
|
||||
raise exceptions.APIException('该半成品无需检测')
|
||||
if 'is_testok' not in vdata:
|
||||
raise exceptions.APIException('未填写检测结论')
|
||||
|
||||
obj = serializer.save(create_by = self.request.user, m_state=vdata['wproduct'].m_state)
|
||||
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)
|
||||
|
||||
# 如果检测合格
|
||||
|
||||
return Response()
|
||||
|
||||
class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
|
||||
"""
|
||||
|
@ -151,6 +184,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
|
|||
action_obj.m_state = vdata['wproducts'][0].m_state
|
||||
action_obj.remark = vdata.get('remark', '') # 操作备注
|
||||
action_obj.create_by = request.user
|
||||
action_obj.use_scrap = vdata.get('use_scrap', False)
|
||||
action_obj.save()
|
||||
|
||||
# 保存物料消耗
|
||||
|
@ -207,7 +241,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
|
|||
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)
|
||||
wproducts.update(p_state=newstep, is_executed=False, pre_pstate=vdata['step'])
|
||||
|
||||
# 特殊情况如果是夹层结合
|
||||
if vdata['step'].type == Step.STEP_TYPE_COMB:
|
||||
|
@ -221,9 +255,10 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
|
|||
parent = data['wproducts']
|
||||
)
|
||||
|
||||
else: # 如果是最后一步, 此时需要转序并更新状态为待检测
|
||||
else: # 如果是最后一步, 此时需要转序并更新状态为待检测, 此时物料状态需变成当前子计划的主产物状态
|
||||
newstep = vdata['step']
|
||||
wproducts.update(p_state=newstep, is_executed=True, act_state=WProduct.WPR_ACT_STATE_TOTEST)
|
||||
wproducts.update(p_state=newstep, is_executed=True,
|
||||
act_state=WProduct.WPR_ACT_STATE_TOTEST, pre_pstate=newstep, m_state=vdata['subproduction_plan'].main_product)
|
||||
|
||||
# 特殊情况如果是夹层结合
|
||||
if vdata['step'].type == Step.STEP_TYPE_COMB:
|
||||
|
|
Loading…
Reference in New Issue