Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop

This commit is contained in:
shilixia 2021-11-16 10:38:24 +08:00
commit fb9f37c993
19 changed files with 479 additions and 116 deletions

View File

@ -0,0 +1,51 @@
# Generated by Django 3.2.6 on 2021-11-12 03:24
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('wpm', '0012_auto_20211111_1056'),
('mtm', '0030_step_need_test'),
('pm', '0012_alter_subproductionprogress_type'),
('inm', '0015_auto_20211111_0940'),
]
operations = [
migrations.RemoveField(
model_name='fifo',
name='subproduction_plan',
),
migrations.RemoveField(
model_name='iproduct',
name='fifos',
),
migrations.RemoveField(
model_name='iproduct',
name='state',
),
migrations.AddField(
model_name='fifoitem',
name='subproduction_plan',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='pm.subproductionplan', verbose_name='关联子生产计划'),
),
migrations.CreateModel(
name='FIFOItemProduct',
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='删除标记')),
('number', models.CharField(max_length=50, verbose_name='物品编号')),
('fifoitem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='inm.fifoitem', verbose_name='关联出入库具体产品')),
('material', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='物料类型')),
('wproduct', models.ForeignKey(blank=True, db_constraint=False, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct', verbose_name='关联的动态产品')),
],
options={
'abstract': False,
},
),
]

View File

@ -67,7 +67,6 @@ class FIFO(CommonAModel):
type = models.IntegerField('出入库类型', default=1)
is_audited = models.BooleanField('是否审核', default=False)
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='')
@ -83,23 +82,25 @@ class FIFOItem(BaseModel):
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)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.DO_NOTHING, null=True, blank=True)
class FIFOItemProduct(BaseModel):
"""
出入库产品
"""
fifoitem = models.ForeignKey(FIFOItem, verbose_name='关联出入库具体产品', on_delete=models.CASCADE)
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
number = models.CharField('物品编号', max_length=50)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
class IProduct(BaseModel):
"""
具体产品条目
"""
inm_product_state_choices = (
(1, '可用'),
(2, '锁定'),
(3, '已消耗')
)
state = models.IntegerField('物品状态', default=1)
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
batch = models.CharField('所属批次号', max_length=100, default='')
wproduct = models.ForeignKey('wpm.wproduct', on_delete=models.CASCADE, verbose_name='关联的动态产品', db_constraint=False, null=True, blank=True)
fifos = models.JSONField('关联出入库记录', default=list, blank=True)

View File

@ -1,6 +1,6 @@
from rest_framework import serializers
from apps.inm.models import FIFO, FIFOItem, IProduct, MaterialBatch, WareHouse,Inventory
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse,Inventory
from apps.qm.models import TestRecord, TestRecordItem
from apps.system.serializers import UserSimpleSerializer
@ -105,14 +105,19 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
raise serializers.ValidationError('数目对不上')
else:
i['fifo'] = obj
fifod = FIFOItem.objects.create(**i)
fifoitem = FIFOItem.objects.create(**i)
p_list0 = []
for x in p_details:
x['material'] = i['material']
x['fifoitem'] = fifoitem
p_list0.append(FIFOItemProduct(**x))
FIFOItemProduct.objects.bulk_create(p_list0)
p_list = []
for x in p_details:
x['state'] = 1
x['material'] = i['material']
x['warehouse'] = validated_data['warehouse']
x['batch'] = i['batch']
x['fifos'] = [fifod.id]
p_list.append(IProduct(**x))
IProduct.objects.bulk_create(p_list)
else:
@ -130,6 +135,7 @@ class InmTestRecordItemCreateSerializer(serializers.ModelSerializer):
class InmTestRecordCreateSerializer(serializers.ModelSerializer):
record_data = InmTestRecordItemCreateSerializer(many=True)
fifo_item = serializers.PrimaryKeyRelatedField(queryset=FIFOItem.objects.all(), required=True)
is_testok = serializers.BooleanField()
class Meta:
model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'fifo_item']

View File

@ -1,14 +1,14 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from apps.inm.models import Inventory, MaterialBatch, FIFO, FIFOItem
from apps.inm.models import FIFOItemProduct, Inventory, MaterialBatch, FIFO, FIFOItem
def update_inm(instance:FIFO, type:int=1):
"""
更新库存(正反)
"""
if instance.type in [FIFO.FIFO_TYPE_PUR_IN]: # 采购入库
if instance.type in [FIFO.FIFO_TYPE_PUR_IN, FIFO.FIFO_TYPE_DO_IN]: # 采购入库, 生产入库
# 更新相关表
for i in FIFOItem.objects.filter(fifo=instance):
material = i.material

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-11-12 03:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0029_step_type'),
]
operations = [
migrations.AddField(
model_name='step',
name='need_test',
field=models.BooleanField(default=False, verbose_name='是否需要过程检验'),
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.2.6 on 2021-11-16 00:41
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0030_step_need_test'),
]
operations = [
migrations.AlterField(
model_name='recordform',
name='name',
field=models.CharField(max_length=100, verbose_name='表格名称'),
),
migrations.AlterField(
model_name='usedstep',
name='subproduction',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='usedstep_subproduction', to='mtm.subproduction', verbose_name='关联生产分解'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-11-16 02:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0031_auto_20211116_0841'),
]
operations = [
migrations.AlterField(
model_name='recordformfield',
name='rule_expression',
field=models.TextField(default='', verbose_name='判定表达式'),
),
]

View File

@ -2,7 +2,7 @@ from django.db import models
from django.db.models.base import Model
import django.utils.timezone as timezone
from django.db.models.query import QuerySet
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
from apps.system.models import Organization
@ -81,6 +81,7 @@ class Step(CommonAModel):
name = models.CharField('工序步骤名称', max_length=100)
number = models.CharField('步骤编号', max_length=100, null=True, blank=True)
instruction_content = models.TextField('相应操作指导', null=True, blank=True)
need_test = models.BooleanField('是否需要过程检验', default=False)
sort = models.IntegerField('排序号', default=1)
equipments = models.ManyToManyField(Equipment, verbose_name='使用设备', related_name='step_equips')
@ -101,7 +102,7 @@ class RecordForm(CommonAModel):
(RF_TYPE_DO, '生产记录'),
(RF_TYPE_TEST, '检验记录')
)
name = models.CharField('表格名称', max_length=100, unique=True)
name = models.CharField('表格名称', max_length=100)
type = models.IntegerField('表格类型', choices=type_choices, default=1)
step = models.ForeignKey(Step, verbose_name='关联子工序', on_delete=models.CASCADE, null=True, blank=True)
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE, null=True, blank=True)
@ -153,7 +154,7 @@ class RecordFormField(CommonAModel):
high_rule = models.IntegerField('上限规则', choices=high_rule_choices, null=True, blank=True)
low_limit = models.FloatField('下限值', null=True, blank=True)
low_rule = models.IntegerField('下限规则', choices=low_rule_choices, null=True, blank=True)
rule_expression = models.JSONField('判定表达式', default=list, help_text='判定表达式, 格式为[{"expression":"{value} > 3 and {value}<10"}] 其中{}用于填充的字段key,运算时会换算成实际的值符合条件返回true,表达式只支持简单的运算或datetime/time运算.以首次匹配成功的条件为准,所以多个条件不要有冲突' )
rule_expression = models.TextField('判定表达式', default='')
class Meta:
verbose_name = '记录表格字段'
@ -177,7 +178,7 @@ class SubProduction(CommonAModel):
verbose_name = '产品生产工序'
verbose_name_plural = verbose_name
class SubprodctionMaterial(CommonAModel):
class SubprodctionMaterial(CommonADModel):
"""
输入/输出物料/工具工装
"""
@ -197,20 +198,20 @@ class SubprodctionMaterial(CommonAModel):
sort = models.IntegerField('排序号', default=1)
class UsedStep(CommonAModel):
class UsedStep(CommonADModel):
"""
涉及的生产子工序
"""
step = models.ForeignKey(Step, verbose_name='子工序', on_delete=models.CASCADE, related_name='usedstep')
remark = models.TextField('生产备注', null=True, blank=True)
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='usedstep_subproduction')
class Meta:
verbose_name = '产品生产子工序'
verbose_name_plural = verbose_name
class TechDoc(CommonAModel):
class TechDoc(CommonADModel):
"""
技术文件
"""

View File

@ -13,6 +13,8 @@ def update_subplan_main(sender, instance, created, **kwargs):
subplan.main_product = instance.material
subplan.main_count = instance.count
subplan.main_count_real = instance.count_real
if subplan.main_count == instance.count_real:
subplan.state = 4
subplan.save()

View File

@ -159,7 +159,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
serializer = SubProductionProgressSerializer(instance=instance, many=True)
return Response(serializer.data)
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=PickNeedSerializer)
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
def pick_need(self, request, pk=None):
"""
领料需求清单/库存数

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-11-16 00:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0008_auto_20211111_1405'),
]
operations = [
migrations.AlterField(
model_name='testrecorditem',
name='is_testok',
field=models.BooleanField(blank=True, null=True, verbose_name='是否合格'),
),
]

View File

@ -66,5 +66,5 @@ class TestRecordItem(BaseModel):
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)
is_testok = models.BooleanField('是否合格', null=True, blank=True)
test_record = models.ForeignKey(TestRecord, verbose_name='关联的检测记录', on_delete=models.CASCADE, related_name='item_test_record')

View File

@ -177,6 +177,18 @@ class CommonAModel(SoftModel):
class Meta:
abstract = True
class CommonADModel(BaseModel):
"""
业务用基本表A,包含create_by, update_by字段, 硬删除
"""
create_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name= '%(class)s_create_by')
update_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name= '%(class)s_update_by')
class Meta:
abstract = True
class CommonBModel(SoftModel):
"""
业务用基本表B,包含create_by, update_by, belong_dept字段
@ -191,6 +203,19 @@ class CommonBModel(SoftModel):
class Meta:
abstract = True
class CommonBDModel(BaseModel):
"""
业务用基本表B,包含create_by, update_by, belong_dept字段, 硬删除
"""
create_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='创建人', related_name = '%(class)s_create_by')
update_by = models.ForeignKey(
User, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='最后编辑人', related_name = '%(class)s_update_by')
belong_dept = models.ForeignKey(
Organization, null=True, blank=True, on_delete=models.SET_NULL, verbose_name='所属部门', related_name= '%(class)s_belong_dept')
class Meta:
abstract = True
class File(CommonAModel):
"""

View File

@ -121,7 +121,7 @@ class WfService(object):
for i in transition.condition_expression:
expression = i['expression'].format(**ticket_all_value)
import datetime, time # 用于支持条件表达式中对时间的操作
if eval(expression, {"__builtins__":None}, {'datetime':datetime, 'time':time}):
if eval(expression, {'__builtins__':None}, {'datetime':datetime, 'time':time}):
destination_state = State.objects.get(pk=i['target_state'])
return destination_state

View File

@ -0,0 +1,25 @@
# Generated by Django 3.2.6 on 2021-11-16 00:41
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('inm', '0016_auto_20211112_1124'),
('wpm', '0012_auto_20211111_1056'),
]
operations = [
migrations.AddField(
model_name='wproduct',
name='warehouse',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='inm.warehouse', verbose_name='所在仓库'),
),
migrations.AlterField(
model_name='wproduct',
name='act_state',
field=models.IntegerField(choices=[(1, '生产中'), (2, '待检测'), (3, '已合格'), (4, '库存中')], default=0, verbose_name='进行状态'),
),
]

View File

@ -2,6 +2,7 @@ from django.db import models
from django.db.models.base import Model
import django.utils.timezone as timezone
from django.db.models.query import QuerySet
from apps.inm.models import WareHouse
from apps.pm.models import ProductionPlan, SubProductionPlan
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
@ -24,10 +25,12 @@ class WProduct(CommonAModel):
WPR_ACT_STATE_DOING = 1
WPR_ACT_STATE_TOTEST = 2
WPR_ACT_STATE_OK = 3
WPR_ACT_STATE_INM = 4
act_state_choices=(
(WPR_ACT_STATE_DOING, '生产中'),
(WPR_ACT_STATE_TOTEST, '待检测'),
(WPR_ACT_STATE_OK, '已合格')
(WPR_ACT_STATE_OK, '已合格'),
(WPR_ACT_STATE_INM, '库存中'),
)
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
m_state = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
@ -40,6 +43,7 @@ class WProduct(CommonAModel):
remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
class Operation(CommonAModel):

View File

@ -17,7 +17,7 @@ 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="领料数量")
pick_count = serializers.IntegerField(label="领料数量", required=False)
class PickSerializer(serializers.Serializer):
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
@ -25,7 +25,7 @@ class PickSerializer(serializers.Serializer):
def create(self, validated_data):
picks = validated_data.pop('picks')
sp = validated_data['subproduction_plan']
sp = validated_data.pop('subproduction_plan')
if sp.state not in [1,2]:
raise exceptions.ValidationError('该子计划状态错误')
if sp.is_picked:
@ -39,15 +39,14 @@ class PickSerializer(serializers.Serializer):
# raise exceptions.ValidationError('物料不存在')
# 创建出库记录
with transaction.atomic():
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)
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), create_by=self.context['request'].user)
for i in picks:
# 更新出库详情
i['count'] = i.pop('pick_count', 0)
if i['count']>0:
i['fifo'] = fifo
i['count'] = i.pop('pick_count')
i['is_testok'] = True # 默认检测合格
i['subproduction_plan'] = sp
FIFOItem.objects.create(**i)
# 更新车间物料
wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
@ -115,17 +114,17 @@ class OperationListSerializer(serializers.ModelSerializer):
class OperationInitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
wproducts = serializers.ListField(child=
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
def validate(self, data):
subproduction_plan = data['subproduction_plan']
# subproduction_plan = data['subproduction_plan']
step = data['step']
stepIds=[i['id'] for i in subproduction_plan.steps]
if step.id not in stepIds:
raise exceptions.ValidationError('请选择正确的子工序操作')
# stepIds=[i['id'] for i in subproduction_plan.steps]
# if step.id not in stepIds:
# raise exceptions.ValidationError('请选择正确的子工序操作')
if 'wproducts' in data and data['wproducts']:
if step.type == Step.STEP_TYPE_DIV:
@ -133,8 +132,8 @@ class OperationInitSerializer(serializers.Serializer):
for i in data['wproducts']:
if i.is_executed:
raise exceptions.ValidationError('不可进行操作')
if i.subproduction_plan != subproduction_plan:
raise exceptions.ValidationError('半成品所属子计划不一致')
# if i.subproduction_plan != subproduction_plan:
# raise exceptions.ValidationError('半成品所属子计划不一致')
if i.p_state != step:
raise exceptions.ValidationError('半成品所属子工序不一致')
else:
@ -148,6 +147,7 @@ class DoInputSerializer(serializers.Serializer):
count_input = serializers.IntegerField(min_value=0, label='消耗数量')
class DoOutputSerializer(serializers.Serializer):
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label='物料ID')
count_output = serializers.IntegerField(min_value=0, label='产出数量')
@ -166,7 +166,7 @@ class OperationRecordSerializer(serializers.ModelSerializer):
class OperationSubmitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
wproducts = serializers.ListField(child=
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
input = DoInputSerializer(many=True, required=False)
@ -183,9 +183,23 @@ class WpmTestRecordItemCreateSerializer(serializers.ModelSerializer):
class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
record_data = WpmTestRecordItemCreateSerializer(many=True)
wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
is_testok = serializers.BooleanField()
class Meta:
model = TestRecord
fields = ['form', 'record_data', 'is_testok', 'wproduct']
class WproductPutInSerializer(serializers.Serializer):
"""
半成品入库序列化
"""
class WplanPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False)
class WproductPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False)

View File

@ -0,0 +1,15 @@
from apps.pm.models import SubProductionPlan
from apps.mtm.models import Step
class WpmServies(object):
@classmethod
def get_next_step(cls, subproduction_plan:SubProductionPlan, nowstep:Step):
"""
获取下一步骤
"""
stepIds = [i['id'] for i in subproduction_plan.steps]
pindex = stepIds.index(nowstep.id)
if pindex + 1 < len(stepIds):
return Step.objects.get(pk=stepIds[pindex+1]), True
else:
return nowstep, False

View File

@ -5,6 +5,8 @@ from rest_framework.utils import serializer_helpers
from rest_framework.utils.field_mapping import get_relation_kwargs
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct
from apps.inm.signals import update_inm
from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial
from apps.mtm.serializers import RecordFormDetailSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress
@ -15,10 +17,13 @@ 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, WpmTestRecordCreateSerializer
from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer
from rest_framework.response import Response
from django.db import transaction
from rest_framework import exceptions
from rest_framework import exceptions, serializers
from apps.wpm.services import WpmServies
from django.utils import timezone
# Create your views here.
class WPlanViewSet(ListModelMixin, GenericViewSet):
"""
@ -29,8 +34,66 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
search_fields = []
serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop']
ordering_fields = ['process__number']
ordering = ['process__number']
ordering_fields = []
ordering = ['-id']
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WplanPutInSerializer)
@transaction.atomic
def putin(self, request, pk=None):
"""
半成品入库
"""
serializer= WplanPutInSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.data
subplan = self.get_object()
material = subplan.main_product
batch = subplan.production_plan.number
wproducts = WProduct.objects.filter(subproduction_plan=subplan,
act_state=WProduct.WPR_ACT_STATE_OK, m_state=material, is_deleted=False)
if wproducts.exists():
# 创建入库记录
remark = vdata.get('remark', '')
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark)
# 创建入库明细
fifoitem = FIFOItem()
fifoitem.is_tested = True
fifoitem.is_testok = True
fifoitem.warehouse = vdata['warehouse']
fifoitem.material = material
fifoitem.count = wproducts.count()
fifoitem.batch = batch
fifoitem.fifo = fifo
fifoitem.subproduction_plan = subplan
fifoitem.save()
# 创建入库明细半成品
ips = []
for i in wproducts:
ip = {}
ip['fifoitem'] = fifoitem
ip['wproduct'] = i
ip['number'] = i.number
ip['material'] = material
ips.append(FIFOItemProduct(**ip))
FIFOItemProduct.objects.bulk_create(ips)
# 创建IProduct
ips2 = []
for i in wproducts:
ip = {}
ip['warehouse'] = vdata['warehouse']
ip['batch'] = batch
ip['wproduct'] = i
ip['number'] = i.number
ip['material'] = material
ips2.append(IProduct(**ip))
IProduct.objects.bulk_create(ips2)
# 更新库存并修改半成品进行状态
update_inm(fifo)
wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=vdata['warehouse'])
return Response()
class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
"""
@ -53,6 +116,63 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
serializer.save()
return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=WproductPutInSerializer)
@transaction.atomic
def putin(self, request, pk=None):
"""
半成品入库
"""
serializer= WproductPutInSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
vdata = serializer.data
wproduct = self.get_object()
if wproduct.act_state != WProduct.WPR_ACT_STATE_OK:
raise exceptions.APIException('半成品不可入库')
material = wproduct.m_state
batch = wproduct.production_plan.number
# 创建入库记录
remark = vdata.get('remark', '')
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
is_audited=True, auditor=request.user, inout_date=timezone.now(), create_by=request.user, remark=remark)
# 创建入库明细
fifoitem = FIFOItem()
fifoitem.is_tested = True
fifoitem.is_testok = True
fifoitem.warehouse = vdata['warehouse']
fifoitem.material = material
fifoitem.count = 1 # 单个半成品入库
fifoitem.batch = batch
fifoitem.fifo = fifo
fifoitem.subproduction_plan = wproduct.subproduction_plan
fifoitem.save()
# 创建入库明细半成品
ips = []
for i in [wproduct]:
ip = {}
ip['fifoitem'] = fifoitem
ip['wproduct'] = i
ip['number'] = i.number
ip['material'] = material
ips.append(FIFOItemProduct(**ip))
FIFOItemProduct.objects.bulk_create(ips)
# 创建IProduct
ips2 = []
for i in [wproduct]:
ip = {}
ip['warehouse'] = vdata['warehouse']
ip['batch'] = batch
ip['wproduct'] = i
ip['number'] = i.number
ip['material'] = material
ips2.append(IProduct(**ip))
IProduct.objects.bulk_create(ips2)
# 更新库存并修改半成品进行状态
update_inm(fifo)
wproduct.act_state=WProduct.WPR_ACT_STATE_INM
wproduct.warehouse=vdata['warehouse']
wproduct.save()
return Response()
class WProductViewSet(ListModelMixin, GenericViewSet):
"""
半成品
@ -60,7 +180,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
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']
filterset_fields = ['p_state', 'subproduction_plan', 'm_state', 'production_plan', 'p_state__process', 'act_state']
search_fields = ['number']
ordering_fields = ['id']
ordering = ['id']
@ -77,7 +197,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
record_data = vdata.pop('record_data')
wproduct = vdata['wproduct']
if wproduct.act_state != WProduct.WPR_ACT_STATE_TOTEST:
raise exceptions.APIException('该半成品无需检测')
raise exceptions.APIException('该半成品不可检测')
if 'is_testok' not in vdata:
raise exceptions.APIException('未填写检测结论')
@ -91,12 +211,25 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
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['is_testok'] = m['is_testok'] if 'is_testok' in m else None
m['test_record'] = obj
tris.append(TestRecordItem(**m))
TestRecordItem.objects.bulk_create(tris)
# 如果检测合格
# 如果检测合格, 变更动态产品进行状态
if obj.is_testok:
vdata['wproduct'].act_state = WProduct.WPR_ACT_STATE_OK
vdata['wproduct'].save()
# 更新子计划状态
# 获取该子计划主产品数, 更新进度
main_count = WProduct.objects.filter(subproduction_plan=wproduct.subproduction_plan, act_stae=WProduct.WPR_ACT_STATE_OK).count()
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = main_count
instance.save()
else:# 如果不合格
pass
return Response()
@ -130,26 +263,37 @@ class DoFormInit(CreateAPIView, GenericAPIView):
ret = {}
ret_0 = {}
ret_0['step'] = data['step']
ret_0['subproduction_plan'] = data['subproduction_plan']
splans =[]
ret_0['input'] = []
# ret_0['subproduction_plan'] = data['subproduction_plan']
if 'wproducts' in data and data['wproducts']:
ret_0['wproducts'] = data['wproducts']
splans = WProduct.objects.filter(id__in=data['wproducts']).values_list('subproduction_plan', flat=True)
# 调出所属子计划现有物料
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(subproduction_plan__in=splans), many=True).data
else:
if 'subproduction_plan' in vdata:
splans = [vdata['subproduction_plan']]
else:
splans = SubProductionPlan.objects.filter(is_deleted=False,
subproduction__usedstep_subproduction__step=vdata['step'], state=3)
ret_0['wproducts'] = []
# 调出该子计划现有物料
ret_0['input'] = list(WMaterial.objects.filter(subproduction_plan=vdata['subproduction_plan'])\
.values('id', 'material', 'material__name', 'count', 'material__number', 'batch'))
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(subproduction_plan__in=splans), many=True).data
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)
subproduction_plan__in=splans, 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'))
subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
ret_0['output'] = list(o_objs.values('subproduction_plan', 'material', 'material__name', 'material__number'))
for i in ret_0['output']:
i['count_output']=0
ret['forms'] = []
@ -206,16 +350,15 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
if 'output' in data and data['output']:
for i in vdata['output']: # 已经序列化好的数据
ma = i['material']
if vdata['subproduction_plan'].main_product == ma: # 如果是该计划主产物
if i['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]),
newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
wpr = dict(m_state=ma, 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)
subproduction_plan=i['subproduction_plan'],
production_plan=i['subproduction_plan'].production_plan)
for x in range(i['count_output']):
WProduct.objects.create(**wpr)
else:
@ -223,53 +366,51 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
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'],
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i['subproduction_plan'],
material=ma)
ins.count = ins.count + i['count_output']
ins.save()
# 更新子计划进度表
sp = SubProductionProgress.objects.get(subproduction_plan=vdata['subproduction_plan'],
sp = SubProductionProgress.objects.get(subproduction_plan=i['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'])
if 'wproducts' in vdata and vdata['wproducts']:
if vdata['step'].type == Step.STEP_TYPE_COMB:
wproducts = vdata['wproducts']
if 'suproduction_plan' in vdata:
wproducts.update(is_hidden=True) # 隐藏
newstep, hasNext = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
wproduct = WProduct()
wproduct.m_state = vdata['subproduction_plan'].main_product
wproduct.p_state = newstep
wproduct.subproduction_plan=vdata['subproduction_plan']
wproduct.production_plan=vdata['subproduction_plan'].production_plan
wproduct.parent = data['wproducts']
if hasNext:
wproduct.act_state=WProduct.WPR_ACT_STATE_DOING
wproduct.is_executed=False
else:
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST
wproduct.is_executed=True
wproduct.save()
else:
raise exceptions.APIException('请指定子计划')
else:
for wproduct in vdata['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, pre_pstate=vdata['step'])
# 特殊情况如果是夹层结合
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, pre_pstate=newstep, m_state=vdata['subproduction_plan'].main_product)
# 特殊情况如果是夹层结合
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
)
newstep, hasNext = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
wproduct.p_state = newstep
wproduct.pre_pstate=vdata['step']
if hasNext:
wproduct.is_executed= False
else:
wproduct.is_executed= True
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST
wproduct.m_state=wproduct.subproduction_plan.main_product
wproduct.save()
# 保存自定义表单结果
for i in vdata['forms']: