Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop
This commit is contained in:
commit
fb9f37c993
|
|
@ -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,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -67,7 +67,6 @@ class FIFO(CommonAModel):
|
||||||
type = models.IntegerField('出入库类型', default=1)
|
type = models.IntegerField('出入库类型', default=1)
|
||||||
is_audited = models.BooleanField('是否审核', default=False)
|
is_audited = models.BooleanField('是否审核', default=False)
|
||||||
auditor = models.ForeignKey(User, verbose_name='审核人', on_delete=models.CASCADE, null=True, blank=True)
|
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('出入库日期')
|
inout_date = models.DateField('出入库日期')
|
||||||
remark = models.CharField('备注', max_length=1000, default='')
|
remark = models.CharField('备注', max_length=1000, default='')
|
||||||
|
|
||||||
|
|
@ -83,23 +82,25 @@ class FIFOItem(BaseModel):
|
||||||
count = models.IntegerField('数量', default=0, validators=[MinValueValidator(0)])
|
count = models.IntegerField('数量', default=0, validators=[MinValueValidator(0)])
|
||||||
batch = models.CharField('批次号', max_length=100, default='')
|
batch = models.CharField('批次号', max_length=100, default='')
|
||||||
fifo = models.ForeignKey(FIFO, verbose_name='关联出入库', on_delete=models.CASCADE)
|
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):
|
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)
|
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
|
||||||
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
|
||||||
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
|
||||||
batch = models.CharField('所属批次号', max_length=100, default='')
|
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)
|
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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
from rest_framework import serializers
|
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.qm.models import TestRecord, TestRecordItem
|
||||||
|
|
||||||
from apps.system.serializers import UserSimpleSerializer
|
from apps.system.serializers import UserSimpleSerializer
|
||||||
|
|
@ -105,14 +105,19 @@ class FIFOInPurSerializer(serializers.ModelSerializer):
|
||||||
raise serializers.ValidationError('数目对不上')
|
raise serializers.ValidationError('数目对不上')
|
||||||
else:
|
else:
|
||||||
i['fifo'] = obj
|
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 = []
|
p_list = []
|
||||||
for x in p_details:
|
for x in p_details:
|
||||||
x['state'] = 1
|
|
||||||
x['material'] = i['material']
|
x['material'] = i['material']
|
||||||
x['warehouse'] = validated_data['warehouse']
|
x['warehouse'] = validated_data['warehouse']
|
||||||
x['batch'] = i['batch']
|
x['batch'] = i['batch']
|
||||||
x['fifos'] = [fifod.id]
|
|
||||||
p_list.append(IProduct(**x))
|
p_list.append(IProduct(**x))
|
||||||
IProduct.objects.bulk_create(p_list)
|
IProduct.objects.bulk_create(p_list)
|
||||||
else:
|
else:
|
||||||
|
|
@ -130,6 +135,7 @@ class InmTestRecordItemCreateSerializer(serializers.ModelSerializer):
|
||||||
class InmTestRecordCreateSerializer(serializers.ModelSerializer):
|
class InmTestRecordCreateSerializer(serializers.ModelSerializer):
|
||||||
record_data = InmTestRecordItemCreateSerializer(many=True)
|
record_data = InmTestRecordItemCreateSerializer(many=True)
|
||||||
fifo_item = serializers.PrimaryKeyRelatedField(queryset=FIFOItem.objects.all(), required=True)
|
fifo_item = serializers.PrimaryKeyRelatedField(queryset=FIFOItem.objects.all(), required=True)
|
||||||
|
is_testok = serializers.BooleanField()
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TestRecord
|
model = TestRecord
|
||||||
fields = ['form', 'record_data', 'is_testok', 'fifo_item']
|
fields = ['form', 'record_data', 'is_testok', 'fifo_item']
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
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, FIFOItem
|
from apps.inm.models import FIFOItemProduct, Inventory, MaterialBatch, FIFO, FIFOItem
|
||||||
|
|
||||||
|
|
||||||
def update_inm(instance:FIFO, type:int=1):
|
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):
|
for i in FIFOItem.objects.filter(fifo=instance):
|
||||||
material = i.material
|
material = i.material
|
||||||
|
|
|
||||||
|
|
@ -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='是否需要过程检验'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -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='关联生产分解'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -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='判定表达式'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -2,7 +2,7 @@ from django.db import models
|
||||||
from django.db.models.base import Model
|
from django.db.models.base import Model
|
||||||
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
|
||||||
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 utils.model import SoftModel, BaseModel
|
||||||
from simple_history.models import HistoricalRecords
|
from simple_history.models import HistoricalRecords
|
||||||
from apps.system.models import Organization
|
from apps.system.models import Organization
|
||||||
|
|
@ -81,6 +81,7 @@ class Step(CommonAModel):
|
||||||
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)
|
||||||
instruction_content = models.TextField('相应操作指导', null=True, blank=True)
|
instruction_content = models.TextField('相应操作指导', null=True, blank=True)
|
||||||
|
need_test = models.BooleanField('是否需要过程检验', default=False)
|
||||||
sort = models.IntegerField('排序号', default=1)
|
sort = models.IntegerField('排序号', default=1)
|
||||||
equipments = models.ManyToManyField(Equipment, verbose_name='使用设备', related_name='step_equips')
|
equipments = models.ManyToManyField(Equipment, verbose_name='使用设备', related_name='step_equips')
|
||||||
|
|
||||||
|
|
@ -101,7 +102,7 @@ class RecordForm(CommonAModel):
|
||||||
(RF_TYPE_DO, '生产记录'),
|
(RF_TYPE_DO, '生产记录'),
|
||||||
(RF_TYPE_TEST, '检验记录')
|
(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)
|
type = models.IntegerField('表格类型', choices=type_choices, default=1)
|
||||||
step = models.ForeignKey(Step, verbose_name='关联子工序', on_delete=models.CASCADE, null=True, blank=True)
|
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)
|
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)
|
high_rule = models.IntegerField('上限规则', choices=high_rule_choices, null=True, blank=True)
|
||||||
low_limit = models.FloatField('下限值', null=True, blank=True)
|
low_limit = models.FloatField('下限值', null=True, blank=True)
|
||||||
low_rule = models.IntegerField('下限规则', choices=low_rule_choices, 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:
|
class Meta:
|
||||||
verbose_name = '记录表格字段'
|
verbose_name = '记录表格字段'
|
||||||
|
|
@ -177,7 +178,7 @@ class SubProduction(CommonAModel):
|
||||||
verbose_name = '产品生产工序'
|
verbose_name = '产品生产工序'
|
||||||
verbose_name_plural = 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)
|
sort = models.IntegerField('排序号', default=1)
|
||||||
|
|
||||||
|
|
||||||
class UsedStep(CommonAModel):
|
class UsedStep(CommonADModel):
|
||||||
"""
|
"""
|
||||||
涉及的生产子工序
|
涉及的生产子工序
|
||||||
"""
|
"""
|
||||||
step = models.ForeignKey(Step, verbose_name='子工序', on_delete=models.CASCADE, related_name='usedstep')
|
step = models.ForeignKey(Step, verbose_name='子工序', on_delete=models.CASCADE, related_name='usedstep')
|
||||||
remark = models.TextField('生产备注', null=True, blank=True)
|
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:
|
class Meta:
|
||||||
verbose_name = '产品生产子工序'
|
verbose_name = '产品生产子工序'
|
||||||
verbose_name_plural = verbose_name
|
verbose_name_plural = verbose_name
|
||||||
|
|
||||||
|
|
||||||
class TechDoc(CommonAModel):
|
class TechDoc(CommonADModel):
|
||||||
"""
|
"""
|
||||||
技术文件
|
技术文件
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ def update_subplan_main(sender, instance, created, **kwargs):
|
||||||
subplan.main_product = instance.material
|
subplan.main_product = instance.material
|
||||||
subplan.main_count = instance.count
|
subplan.main_count = instance.count
|
||||||
subplan.main_count_real = instance.count_real
|
subplan.main_count_real = instance.count_real
|
||||||
|
if subplan.main_count == instance.count_real:
|
||||||
|
subplan.state = 4
|
||||||
subplan.save()
|
subplan.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -159,7 +159,7 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
|
||||||
serializer = SubProductionProgressSerializer(instance=instance, many=True)
|
serializer = SubProductionProgressSerializer(instance=instance, many=True)
|
||||||
return Response(serializer.data)
|
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):
|
def pick_need(self, request, pk=None):
|
||||||
"""
|
"""
|
||||||
领料需求清单/库存数
|
领料需求清单/库存数
|
||||||
|
|
|
||||||
|
|
@ -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='是否合格'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -66,5 +66,5 @@ class TestRecordItem(BaseModel):
|
||||||
field_value = models.JSONField('录入值', default=dict, blank=True)
|
field_value = models.JSONField('录入值', default=dict, blank=True)
|
||||||
need_judge = models.BooleanField('是否需要判定', default=False)
|
need_judge = models.BooleanField('是否需要判定', default=False)
|
||||||
sort = models.IntegerField('排序号', default=1)
|
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')
|
test_record = models.ForeignKey(TestRecord, verbose_name='关联的检测记录', on_delete=models.CASCADE, related_name='item_test_record')
|
||||||
|
|
@ -177,6 +177,18 @@ class CommonAModel(SoftModel):
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
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):
|
class CommonBModel(SoftModel):
|
||||||
"""
|
"""
|
||||||
业务用基本表B,包含create_by, update_by, belong_dept字段
|
业务用基本表B,包含create_by, update_by, belong_dept字段
|
||||||
|
|
@ -191,6 +203,19 @@ class CommonBModel(SoftModel):
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
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):
|
class File(CommonAModel):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ class WfService(object):
|
||||||
for i in transition.condition_expression:
|
for i in transition.condition_expression:
|
||||||
expression = i['expression'].format(**ticket_all_value)
|
expression = i['expression'].format(**ticket_all_value)
|
||||||
import datetime, time # 用于支持条件表达式中对时间的操作
|
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'])
|
destination_state = State.objects.get(pk=i['target_state'])
|
||||||
return destination_state
|
return destination_state
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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='进行状态'),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -2,6 +2,7 @@ from django.db import models
|
||||||
from django.db.models.base import Model
|
from django.db.models.base import Model
|
||||||
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
|
||||||
|
from apps.inm.models import WareHouse
|
||||||
from apps.pm.models import ProductionPlan, SubProductionPlan
|
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
|
||||||
|
|
@ -24,10 +25,12 @@ class WProduct(CommonAModel):
|
||||||
WPR_ACT_STATE_DOING = 1
|
WPR_ACT_STATE_DOING = 1
|
||||||
WPR_ACT_STATE_TOTEST = 2
|
WPR_ACT_STATE_TOTEST = 2
|
||||||
WPR_ACT_STATE_OK = 3
|
WPR_ACT_STATE_OK = 3
|
||||||
|
WPR_ACT_STATE_INM = 4
|
||||||
act_state_choices=(
|
act_state_choices=(
|
||||||
(WPR_ACT_STATE_DOING, '生产中'),
|
(WPR_ACT_STATE_DOING, '生产中'),
|
||||||
(WPR_ACT_STATE_TOTEST, '待检测'),
|
(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)
|
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)
|
||||||
|
|
@ -40,6 +43,7 @@ class WProduct(CommonAModel):
|
||||||
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)
|
||||||
|
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
|
||||||
|
|
||||||
|
|
||||||
class Operation(CommonAModel):
|
class Operation(CommonAModel):
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class PickDetailSerializer(serializers.Serializer):
|
||||||
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
|
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label="物料ID")
|
||||||
batch = serializers.CharField(label='物料批次', allow_blank=True)
|
batch = serializers.CharField(label='物料批次', allow_blank=True)
|
||||||
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
|
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):
|
class PickSerializer(serializers.Serializer):
|
||||||
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
|
subproduction_plan=serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID")
|
||||||
|
|
@ -25,7 +25,7 @@ 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.pop('subproduction_plan')
|
||||||
if sp.state not in [1,2]:
|
if sp.state not in [1,2]:
|
||||||
raise exceptions.ValidationError('该子计划状态错误')
|
raise exceptions.ValidationError('该子计划状态错误')
|
||||||
if sp.is_picked:
|
if sp.is_picked:
|
||||||
|
|
@ -39,15 +39,14 @@ class PickSerializer(serializers.Serializer):
|
||||||
# raise exceptions.ValidationError('物料不存在')
|
# raise exceptions.ValidationError('物料不存在')
|
||||||
# 创建出库记录
|
# 创建出库记录
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
validated_data['create_by'] = self.context['request'].user
|
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_OUT, inout_date=timezone.now(), 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)
|
|
||||||
for i in picks:
|
for i in picks:
|
||||||
# 更新出库详情
|
# 更新出库详情
|
||||||
|
i['count'] = i.pop('pick_count', 0)
|
||||||
|
if i['count']>0:
|
||||||
i['fifo'] = fifo
|
i['fifo'] = fifo
|
||||||
i['count'] = i.pop('pick_count')
|
|
||||||
i['is_testok'] = True # 默认检测合格
|
i['is_testok'] = True # 默认检测合格
|
||||||
|
i['subproduction_plan'] = sp
|
||||||
FIFOItem.objects.create(**i)
|
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'], \
|
||||||
|
|
@ -115,17 +114,17 @@ class OperationListSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class OperationInitSerializer(serializers.Serializer):
|
class OperationInitSerializer(serializers.Serializer):
|
||||||
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
|
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=
|
wproducts = serializers.ListField(child=
|
||||||
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
|
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
subproduction_plan = data['subproduction_plan']
|
# subproduction_plan = data['subproduction_plan']
|
||||||
step = data['step']
|
step = data['step']
|
||||||
|
|
||||||
stepIds=[i['id'] for i in subproduction_plan.steps]
|
# stepIds=[i['id'] for i in subproduction_plan.steps]
|
||||||
if step.id not in stepIds:
|
# if step.id not in stepIds:
|
||||||
raise exceptions.ValidationError('请选择正确的子工序操作')
|
# raise exceptions.ValidationError('请选择正确的子工序操作')
|
||||||
|
|
||||||
if 'wproducts' in data and data['wproducts']:
|
if 'wproducts' in data and data['wproducts']:
|
||||||
if step.type == Step.STEP_TYPE_DIV:
|
if step.type == Step.STEP_TYPE_DIV:
|
||||||
|
|
@ -133,8 +132,8 @@ class OperationInitSerializer(serializers.Serializer):
|
||||||
for i in data['wproducts']:
|
for i in data['wproducts']:
|
||||||
if i.is_executed:
|
if i.is_executed:
|
||||||
raise exceptions.ValidationError('不可进行操作')
|
raise exceptions.ValidationError('不可进行操作')
|
||||||
if i.subproduction_plan != subproduction_plan:
|
# if i.subproduction_plan != subproduction_plan:
|
||||||
raise exceptions.ValidationError('半成品所属子计划不一致')
|
# raise exceptions.ValidationError('半成品所属子计划不一致')
|
||||||
if i.p_state != step:
|
if i.p_state != step:
|
||||||
raise exceptions.ValidationError('半成品所属子工序不一致')
|
raise exceptions.ValidationError('半成品所属子工序不一致')
|
||||||
else:
|
else:
|
||||||
|
|
@ -148,6 +147,7 @@ class DoInputSerializer(serializers.Serializer):
|
||||||
count_input = serializers.IntegerField(min_value=0, label='消耗数量')
|
count_input = serializers.IntegerField(min_value=0, label='消耗数量')
|
||||||
|
|
||||||
class DoOutputSerializer(serializers.Serializer):
|
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')
|
material = serializers.PrimaryKeyRelatedField(queryset=Material.objects.all(), label='物料ID')
|
||||||
count_output = serializers.IntegerField(min_value=0, label='产出数量')
|
count_output = serializers.IntegerField(min_value=0, label='产出数量')
|
||||||
|
|
||||||
|
|
@ -166,7 +166,7 @@ class OperationRecordSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
class OperationSubmitSerializer(serializers.Serializer):
|
class OperationSubmitSerializer(serializers.Serializer):
|
||||||
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
|
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=
|
wproducts = serializers.ListField(child=
|
||||||
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
|
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
|
||||||
input = DoInputSerializer(many=True, required=False)
|
input = DoInputSerializer(many=True, required=False)
|
||||||
|
|
@ -183,9 +183,23 @@ class WpmTestRecordItemCreateSerializer(serializers.ModelSerializer):
|
||||||
class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
|
class WpmTestRecordCreateSerializer(serializers.ModelSerializer):
|
||||||
record_data = WpmTestRecordItemCreateSerializer(many=True)
|
record_data = WpmTestRecordItemCreateSerializer(many=True)
|
||||||
wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
|
wproduct = serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), required=True)
|
||||||
|
is_testok = serializers.BooleanField()
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TestRecord
|
model = TestRecord
|
||||||
fields = ['form', 'record_data', 'is_testok', 'wproduct']
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -5,6 +5,8 @@ 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.views import APIView
|
||||||
from rest_framework.viewsets import GenericViewSet, ModelViewSet
|
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.models import Material, RecordForm, Step, SubprodctionMaterial
|
||||||
from apps.mtm.serializers import RecordFormDetailSerializer
|
from apps.mtm.serializers import RecordFormDetailSerializer
|
||||||
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
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 rest_framework.decorators import action
|
||||||
from apps.wpm.models import WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
|
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 rest_framework.response import Response
|
||||||
from django.db import transaction
|
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.
|
# Create your views here.
|
||||||
class WPlanViewSet(ListModelMixin, GenericViewSet):
|
class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -29,8 +34,66 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
||||||
search_fields = []
|
search_fields = []
|
||||||
serializer_class = SubProductionPlanListSerializer
|
serializer_class = SubProductionPlanListSerializer
|
||||||
filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop']
|
filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop']
|
||||||
ordering_fields = ['process__number']
|
ordering_fields = []
|
||||||
ordering = ['process__number']
|
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):
|
class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
|
|
@ -53,6 +116,63 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
|
||||||
serializer.save()
|
serializer.save()
|
||||||
return Response()
|
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):
|
class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
"""
|
"""
|
||||||
半成品
|
半成品
|
||||||
|
|
@ -60,7 +180,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
perms_map={'*':'*'}
|
perms_map={'*':'*'}
|
||||||
queryset = WProduct.objects.select_related('p_state', 'm_state').filter(is_hidden=False)
|
queryset = WProduct.objects.select_related('p_state', 'm_state').filter(is_hidden=False)
|
||||||
serializer_class = WProductListSerializer
|
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']
|
search_fields = ['number']
|
||||||
ordering_fields = ['id']
|
ordering_fields = ['id']
|
||||||
ordering = ['id']
|
ordering = ['id']
|
||||||
|
|
@ -77,7 +197,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
record_data = vdata.pop('record_data')
|
record_data = vdata.pop('record_data')
|
||||||
wproduct = vdata['wproduct']
|
wproduct = vdata['wproduct']
|
||||||
if wproduct.act_state != WProduct.WPR_ACT_STATE_TOTEST:
|
if wproduct.act_state != WProduct.WPR_ACT_STATE_TOTEST:
|
||||||
raise exceptions.APIException('该半成品无需检测')
|
raise exceptions.APIException('该半成品不可检测')
|
||||||
if 'is_testok' not in vdata:
|
if 'is_testok' not in vdata:
|
||||||
raise exceptions.APIException('未填写检测结论')
|
raise exceptions.APIException('未填写检测结论')
|
||||||
|
|
||||||
|
|
@ -91,12 +211,25 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
||||||
m['field_value'] = m['field_value']
|
m['field_value'] = m['field_value']
|
||||||
m['sort'] = form_field.sort
|
m['sort'] = form_field.sort
|
||||||
m['need_judge'] = form_field.need_judge
|
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
|
m['test_record'] = obj
|
||||||
tris.append(TestRecordItem(**m))
|
tris.append(TestRecordItem(**m))
|
||||||
TestRecordItem.objects.bulk_create(tris)
|
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()
|
return Response()
|
||||||
|
|
||||||
|
|
@ -130,26 +263,37 @@ class DoFormInit(CreateAPIView, GenericAPIView):
|
||||||
ret = {}
|
ret = {}
|
||||||
ret_0 = {}
|
ret_0 = {}
|
||||||
ret_0['step'] = data['step']
|
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']:
|
if 'wproducts' in data and data['wproducts']:
|
||||||
ret_0['wproducts'] = 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:
|
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['wproducts'] = []
|
||||||
# 调出该子计划现有物料
|
ret_0['input'] = WMaterialListSerializer(instance=WMaterial.objects.filter(subproduction_plan__in=splans), many=True).data
|
||||||
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']:
|
for i in ret_0['input']:
|
||||||
i['count_input'] = 0
|
i['count_input'] = 0
|
||||||
# 需要输出的物料
|
# 需要输出的物料
|
||||||
if ret_0['wproducts']:
|
if ret_0['wproducts']:
|
||||||
# 排除主要产物, 因为已经放到半成品里了, 由半成品进行处理, 夹层可能需要特殊处理
|
# 排除主要产物, 因为已经放到半成品里了, 由半成品进行处理, 夹层可能需要特殊处理
|
||||||
o_objs = SubProductionProgress.objects.filter(
|
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:
|
else:
|
||||||
|
# 此时显示所有子计划需要输出的物料
|
||||||
o_objs = SubProductionProgress.objects.filter(
|
o_objs = SubProductionProgress.objects.filter(
|
||||||
subproduction_plan=vdata['subproduction_plan'], type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
subproduction_plan__in=splans, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
|
||||||
ret_0['output'] = list(o_objs.values('material', 'material__name', 'material__number'))
|
ret_0['output'] = list(o_objs.values('subproduction_plan', 'material', 'material__name', 'material__number'))
|
||||||
for i in ret_0['output']:
|
for i in ret_0['output']:
|
||||||
i['count_output']=0
|
i['count_output']=0
|
||||||
ret['forms'] = []
|
ret['forms'] = []
|
||||||
|
|
@ -206,16 +350,15 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
|
||||||
if 'output' in data and data['output']:
|
if 'output' in data and data['output']:
|
||||||
for i in vdata['output']: # 已经序列化好的数据
|
for i in vdata['output']: # 已经序列化好的数据
|
||||||
ma = i['material']
|
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:
|
if vdata['step'].type == Step.STEP_TYPE_DIV:
|
||||||
stepIds = [i['id'] for i in vdata['subproduction_plan'].steps]
|
newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
|
||||||
pindex = stepIds.index(vdata['step'].id)
|
wpr = dict(m_state=ma, p_state=newstep,
|
||||||
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='',
|
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
|
||||||
subproduction_plan=vdata['subproduction_plan'],
|
subproduction_plan=i['subproduction_plan'],
|
||||||
production_plan=vdata['subproduction_plan'].production_plan)
|
production_plan=i['subproduction_plan'].production_plan)
|
||||||
for x in range(i['count_output']):
|
for x in range(i['count_output']):
|
||||||
WProduct.objects.create(**wpr)
|
WProduct.objects.create(**wpr)
|
||||||
else:
|
else:
|
||||||
|
|
@ -223,53 +366,51 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
|
||||||
OperationMaterial.objects.create(type=2, operation=action_obj,
|
OperationMaterial.objects.create(type=2, operation=action_obj,
|
||||||
material= ma, count=i['count_output'])
|
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)
|
material=ma)
|
||||||
ins.count = ins.count + i['count_output']
|
ins.count = ins.count + i['count_output']
|
||||||
ins.save()
|
ins.save()
|
||||||
# 更新子计划进度表
|
# 更新子计划进度表
|
||||||
sp = SubProductionProgress.objects.get(subproduction_plan=vdata['subproduction_plan'],
|
sp = SubProductionProgress.objects.get(subproduction_plan=i['subproduction_plan'],
|
||||||
material=ma)
|
material=ma)
|
||||||
sp.count_real = sp.count_real + i['count_input']
|
sp.count_real = sp.count_real + i['count_input']
|
||||||
sp.save()
|
sp.save()
|
||||||
|
|
||||||
# 更新动态产品表
|
# 更新动态产品表
|
||||||
if 'wproducts' in data and data['wproducts']:
|
if 'wproducts' in vdata and vdata['wproducts']:
|
||||||
wproducts = WProduct.objects.filter(pk__in=data['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]
|
newstep, hasNext = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
|
||||||
pindex = stepIds.index(vdata['step'].id)
|
wproduct.p_state = newstep
|
||||||
if pindex + 1 < len(stepIds): # 如果不是最后一步
|
wproduct.pre_pstate=vdata['step']
|
||||||
newstep = Step.objects.get(pk=stepIds[pindex+1])
|
if hasNext:
|
||||||
wproducts.update(p_state=newstep, is_executed=False, pre_pstate=vdata['step'])
|
wproduct.is_executed= False
|
||||||
|
else:
|
||||||
# 特殊情况如果是夹层结合
|
wproduct.is_executed= True
|
||||||
if vdata['step'].type == Step.STEP_TYPE_COMB:
|
wproduct.act_state=WProduct.WPR_ACT_STATE_TOTEST
|
||||||
wproducts.update(is_hidden=True) # 隐藏
|
wproduct.m_state=wproduct.subproduction_plan.main_product
|
||||||
|
wproduct.save()
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
# 保存自定义表单结果
|
# 保存自定义表单结果
|
||||||
for i in vdata['forms']:
|
for i in vdata['forms']:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue