生产操作提交

This commit is contained in:
caoqianming 2021-11-08 09:03:15 +08:00
parent 1b7190a4b6
commit 9588562390
7 changed files with 305 additions and 24 deletions

View File

@ -75,6 +75,11 @@ class FIFODetailViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
ordering_fields = ['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):
"""
出入库记录

View File

@ -1,5 +1,8 @@
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 utils.model import BaseModel
# Create your models here.
class Standard(CommonAModel):
"""
@ -49,4 +52,17 @@ class TestRecord(CommonAModel):
record_data = models.JSONField('记录数据', default=dict, blank=True)
is_testok = models.BooleanField('是否合格', default=True)
fifo_detail = models.ForeignKey('inm.fifodetail', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True)
class TestRecordDetail(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.IntegerField('字段类型', choices=RecordForm.type_choices)
field_value = models.JSONField('录入值', default=dict, blank=True)
need_judge = models.BooleanField('是否需要判定', default=False)
is_testok = models.BooleanField('是否合格', default=True)
test_record = models.ForeignKey(TestRecord, verbose_name='关联的检测记录', on_delete=models.CASCADE)

View File

@ -0,0 +1,114 @@
# 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.AlterField(
model_name='wproduct',
name='parent',
field=models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', 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,
),
]

View File

@ -6,7 +6,7 @@ from apps.pm.models import ProductionPlan, SubProductionPlan
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
from apps.mtm.models import Material, Process, Step, RecordForm
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm
class WMaterial(BaseModel):
"""
@ -44,7 +44,7 @@ class WProductAction(CommonAModel):
生产操作
"""
wproducts = models.JSONField('关联产品ID列表', default=list, blank=True)
m_state = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
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)
@ -58,7 +58,8 @@ class WProductMaterial(BaseModel):
)
type = models.IntegerField('类型', default=0, choices=type_choices)
wproduct_action = models.ForeignKey(WProductAction, verbose_name='关联的生产操作', on_delete=models.CASCADE)
material = models.ForeignKey(Material, 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 WProductRecord(CommonAModel):
@ -66,5 +67,18 @@ class WProductRecord(CommonAModel):
记录表格
"""
form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE)
record_data = models.JSONField('记录的数据', default=dict, blank=True)
wproduct_action = models.ForeignKey(WProductAction, verbose_name='关联的生产操作', on_delete=models.CASCADE)
class WProductRecordDetail(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.IntegerField('字段类型', choices=RecordForm.type_choices)
field_value = models.JSONField('录入值', default=dict, blank=True)
sort = models.IntegerField('排序号', default=1)
wproduct_record = models.ForeignKey(WProductRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE)

View File

@ -2,13 +2,13 @@ from rest_framework import serializers
from rest_framework.serializers import ModelSerializer
from apps.inm.models import FIFO, FIFODetail, MaterialBatch, WareHouse
from apps.inm.signals import update_inm
from apps.mtm.models import Material, Step
from apps.mtm.models import Material, RecordForm, Step
from apps.mtm.serializers import MaterialSimpleSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress
from django.utils import timezone
from apps.wpm.models import WMaterial, WProduct
from apps.wpm.models import WMaterial, WProduct, WProductRecord
class PickDetailSerializer(serializers.Serializer):
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
@ -81,8 +81,41 @@ class WMaterialListSerializer(serializers.ModelSerializer):
fields = '__all__'
class DoFormInitSerializer(serializers.Serializer):
class WActionInitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
wproducts = serializers.ListField(child=
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
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 WProductRecordDetailSerializer(serializers.ModelSerializer):
class Meta:
model = WProductRecord
fields = ['form_field', 'field_value']
class WProductRecordSerializer(serializers.ModelSerializer):
record_data = WProductRecordDetailSerializer(many=True)
class Meta:
model = WProductRecord
fields = ['form', 'record_data']
class WActionSubmitSerializer(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 = WProductRecordSerializer(many=True, required=False)

View File

@ -3,13 +3,14 @@ from rest_framework import urlpatterns
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.wpm.views import DoFormInit, WMaterialViewSet, WPlanViewSet
from apps.wpm.views import DoFormInit, DoFormSubmit, WMaterialViewSet, WPlanViewSet
router = DefaultRouter()
router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
router.register('subplan', WPlanViewSet, basename='wplan')
urlpatterns = [
path('do/init/', DoFormInit.as_view()),
path('do/submit/', DoFormSubmit.as_view()),
path('', include(router.urls)),
]

View File

@ -1,19 +1,20 @@
from django.shortcuts import render
from rest_framework.generics import CreateAPIView, GenericAPIView
from rest_framework.mixins import ListModelMixin
from rest_framework.utils import serializer_helpers
from rest_framework.utils.field_mapping import get_relation_kwargs
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.mtm.models import RecordForm
from apps.mtm.models import Material, RecordForm, Step
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 rest_framework.decorators import action
from apps.wpm.models import WMaterial
from apps.wpm.models import WMaterial, WProduct, WProductAction, WProductMaterial, WProductRecord, WProductRecordDetail
from apps.wpm.serializers import DoFormInitSerializer, PickSerializer, WMaterialListSerializer
from apps.wpm.serializers import PickSerializer, WActionInitSerializer, WActionSubmitSerializer, WMaterialListSerializer
from rest_framework.response import Response
# Create your views here.
class WPlanViewSet(ListModelMixin, GenericViewSet):
@ -49,29 +50,42 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
serializer.save()
return Response()
class DoFormInit(APIView):
class DoFormInit(CreateAPIView, GenericAPIView):
perms_map={'*':'*'}
serializer_class=WActionInitSerializer
def post(self, request, format=None):
"""
调用操作表单
"""
serializer = DoFormInitSerializer(data=request.data)
data = request.data
serializer = WActionInitSerializer(data=data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data
ret = {}
ret['step'] = data['step']
ret['subproduction_plan'] = data['subproduction_plan']
if 'wproducts' in data and data['wproducts']:
ret['wproducts'] = data['wproducts']
else:
ret['wproducts'] = []
# 调出该子计划现有物料
ret['input'] = list(WMaterial.objects.filter(subproduction_plan=vdata['subproduction_plan'])\
.values('material', 'material__name', 'count'))
.values('id', 'material', 'material__name', 'count', 'material__number', 'batch'))
for i in ret['input']:
i['count_input'] = 0
# 需要输出的物料
# 如果传入半成品列表就不需要
if not 'wproducts' in vdata:
ret['output'] = list(SubProductionProgress.objects.filter(subproduction_plan=vdata['subproduction_plan'], type=2)\
.values('material', 'material__name'))
for i in ret['output']:
i['count_output']=0
if ret['wproducts']:
# 排除wproduct列表
# mids = WProduct.objects.filter(pk__in=data['wproducts']).values_list('m_state', flat=True)
o_objs = SubProductionProgress.objects.filter(
subproduction_plan=vdata['subproduction_plan'], type=2).exclude(is_main=True)
else:
o_objs = SubProductionProgress.objects.filter(
subproduction_plan=vdata['subproduction_plan'], type=2)
ret['output'] = list(o_objs.values('material', 'material__name', 'material__number'))
for i in ret['output']:
i['count_output']=0
ret['forms'] = []
forms = RecordForm.objects.filter(step=vdata['step'], type=1)
if forms.exists():
@ -79,8 +93,92 @@ class DoFormInit(APIView):
return Response(ret)
class DoFormSubmit(APIView):
class DoFormSubmit(CreateAPIView, GenericAPIView):
perms_map={'*':'*'}
serializer_class = WActionSubmitSerializer
def post(self, request, format=None):
"""
提交操作表单
"""
"""
data = request.data
serializer = WActionInitSerializer(data=data)
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data #校验之后的数据
# 创建一个生产操作记录
action_obj = WProductAction()
action_obj.p_state = vdata['step']
if 'wproducts' in data and data['wproducts']:
action_obj.wproducts = data['wproducts']
action_obj.m_state = vdata[0].m_state
action_obj.remark = data['remark'] # 操作备注
action_obj.create_by = request.user
action_obj.save()
# 保存物料消耗
for i in vdata['input']:
if i['count_input']: #如果有消耗
i_wmat = i['id']
WProductMaterial.objects.create(type=1, wproduct_action=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 ma.is_main:
# 计划开始, 第一步切割创建动态产品
wpr = dict(m_state=ma, p_state=vdata['step'],
act_state=1, is_executed=True, 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:
# 更新操作消耗物料表
WProductMaterial.objects.create(type=2, wproduct_action=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'])
wproducts.update(p_state=vdata['step'], is_executed=True)
# 保存自定义表单结果
for i in vdata['forms']:
wr = WProductRecord()
wr.form = i['form']
wr.create_by = request.user
wr.wproduct_action = 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'] = form_field.field_value
m['sort'] = form_field.sort
m['wproduct_record'] = wr
wrds.append(WProductRecordDetail(**m))
WProductRecordDetail.objects.bulk_create(wrds)
return Response()