车间物料表修改对应子计划

This commit is contained in:
caoqianming 2021-11-04 09:16:12 +08:00
parent b6dca27688
commit 29a0a0d33a
14 changed files with 220 additions and 23 deletions

View File

@ -74,7 +74,7 @@ class FIFODetailViewSet(ListModelMixin, GenericViewSet):
search_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
class FIFOViewSet(ListModelMixin, GenericViewSet):
"""
出入库记录
@ -111,6 +111,8 @@ class FIFOViewSet(ListModelMixin, GenericViewSet):
for i in FIFODetail.objects.filter(fifo=obj):
if not i.is_testok:
raise APIException('未检验通过, 不可审核')
if obj.is_audited:
raise APIException('该入库记录已审核通过')
obj.is_audited = True
obj.save()
update_inm(obj) # 更新库存

View File

@ -61,6 +61,11 @@ class StepDetailSerializer(serializers.ModelSerializer):
queryset = queryset.prefetch_related('equipments')
return queryset
class SubProductionSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = SubProduction
fields = ['id', 'name']
class SubProductionSerializer(serializers.ModelSerializer):
process_ = ProcessSimpleSerializer(source='process', read_only=True)
class Meta:

View File

@ -5,3 +5,5 @@ class SamConfig(AppConfig):
verbose_name = '生产计划管理'
def ready(self):
import apps.pm.signals

View File

@ -0,0 +1,53 @@
# Generated by Django 3.2.6 on 2021-11-03 09:00
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('mtm', '0028_auto_20211102_1707'),
('pm', '0009_auto_20211029_1017'),
]
operations = [
migrations.AddField(
model_name='subproductionplan',
name='main_count',
field=models.IntegerField(default=1, verbose_name='应产出数'),
preserve_default=False,
),
migrations.AddField(
model_name='subproductionplan',
name='main_count_real',
field=models.IntegerField(default=0, verbose_name='实际产出数'),
),
migrations.AddField(
model_name='subproductionplan',
name='main_product',
field=models.ForeignKey(default=19, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='主要产品'),
preserve_default=False,
),
migrations.AddField(
model_name='subproductionprogress',
name='count_pick',
field=models.IntegerField(default=0, verbose_name='实际领用数'),
),
migrations.AddField(
model_name='subproductionprogress',
name='is_main',
field=models.BooleanField(default=False, verbose_name='是否主产出'),
),
migrations.AlterField(
model_name='subproductionprogress',
name='count',
field=models.IntegerField(verbose_name='应出入数'),
),
migrations.AlterField(
model_name='subproductionprogress',
name='count_real',
field=models.IntegerField(default=0, verbose_name='实际消耗/产出数'),
),
]

View File

@ -43,9 +43,16 @@ class SubProductionPlan(CommonAModel):
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE)
start_date = models.DateField('计划开工日期')
end_date = models.DateField('计划完工日期')
workshop = models.ForeignKey(Organization, verbose_name='生产车间', on_delete=models.CASCADE)
process = models.ForeignKey(Process, verbose_name='关联大工序', on_delete=models.CASCADE)
main_product = models.ForeignKey(Material, verbose_name='主要产品', on_delete=models.CASCADE)
main_count = models.IntegerField('应产出数')
main_count_real = models.IntegerField('实际产出数', default=0)
steps = models.JSONField('工艺步骤', default=list)
state = models.IntegerField('状态', default=0)
start_date_real = models.DateField('实际开工日期', null=True, blank=True)
end_date_real = models.DateField('实际完工日期', null=True, blank=True)
@ -65,6 +72,8 @@ class SubProductionProgress(BaseModel):
)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子生产计划', on_delete=models.CASCADE, related_name='progress_subplan')
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
is_main = models.BooleanField('是否主产出', default=False)
type = models.IntegerField('物料应用类型', default=1)
count = models.FloatField('应出入数')
count_real = models.IntegerField('实际出入数', default=0)
count = models.IntegerField('应出入数')
count_pick = models.IntegerField('实际领用数', default=0)
count_real = models.IntegerField('实际消耗/产出数', default=0)

View File

@ -1,7 +1,7 @@
from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
from rest_framework import serializers
from apps.sam.serializers import OrderSerializer
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer
from apps.mtm.serializers import MaterialSimpleSerializer, ProcessSimpleSerializer, SubProductionSimpleSerializer
from apps.system.serializers import OrganizationSimpleSerializer
@ -27,10 +27,15 @@ class ResourceCalListSerializer(serializers.ListSerializer):
class SubProductionPlanListSerializer(serializers.ModelSerializer):
workshop_ = OrganizationSimpleSerializer(source='workshop', read_only=True)
process_ = ProcessSimpleSerializer(source='process', read_only=True)
subproduction_ = SubProductionSimpleSerializer(source='subproduction', read_only=True)
main_product_ = MaterialSimpleSerializer(source='main_product', read_only=True)
class Meta:
model=SubProductionPlan
fields = '__all__'
class SubProductionPlanUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = SubProductionPlan

View File

@ -0,0 +1,18 @@
from django.db.models.signals import post_save
from django.dispatch import receiver
from apps.pm.models import SubProductionProgress
@receiver(post_save, sender=SubProductionProgress)
def update_subplan_main(sender, instance, created, **kwargs):
"""
根据生产进度统计表更新子计划进度表相关字段
"""
if instance.is_main:
subplan = instance.subproduction_plan
if created:
subplan.main_product = instance.material
subplan.main_count = instance.count
subplan.main_count_real = instance.count_real
subplan.save()

View File

@ -87,8 +87,11 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
start_date=production_plan.start_date, end_date=production_plan.end_date,
workshop=i.process.workshop, process=i.process, create_by=request.user,
steps = list(steps))
# 生成子计划物料需求/进度
for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
SubProductionProgress.objects.create(material=m.material, type=m.type, count=m.count*production_plan.count, subproduction_plan=instance)
spro = SubProductionProgress.objects.create(material=m.material, type=m.type,
is_main=m.is_main,
count=m.count*production_plan.count, subproduction_plan=instance)
production_plan.is_planed=True
production_plan.save()
return Response()
@ -98,10 +101,10 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
子生产计划-列表/修改
"""
perms_map = {'*': '*'}
queryset = SubProductionPlan.objects.select_related('process', 'workshop')
queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'main_product')
search_fields = []
serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan', 'process', 'state']
filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop']
ordering_fields = ['process__number']
ordering = ['process__number']

View File

@ -0,0 +1,61 @@
# Generated by Django 3.2.6 on 2021-11-04 01:14
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('pm', '0010_auto_20211103_1700'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('mtm', '0028_auto_20211102_1707'),
('wpm', '0003_auto_20211102_0935'),
]
operations = [
migrations.CreateModel(
name='WProductRecord',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('data', models.JSONField(blank=True, default=dict, verbose_name='记录的数据')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('record_form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.recordform', verbose_name='所用表格')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='wproductrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
migrations.RemoveField(
model_name='wmaterial',
name='process',
),
migrations.RemoveField(
model_name='wmaterial',
name='workshop',
),
migrations.RemoveField(
model_name='wproductflow',
name='wproduct',
),
migrations.AddField(
model_name='wmaterial',
name='subproduction_plan',
field=models.ForeignKey(default=68, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联子计划'),
preserve_default=False,
),
migrations.AddField(
model_name='wproductflow',
name='wproducts',
field=models.JSONField(default=list, verbose_name='关联产品'),
),
migrations.DeleteModel(
name='WProductForm',
),
]

View File

@ -12,8 +12,9 @@ class WMaterial(BaseModel):
"""
车间生产物料
"""
workshop = models.ForeignKey(Organization, verbose_name='生产车间', on_delete=models.CASCADE)
process = models.ForeignKey(Process, verbose_name='关联大工序', on_delete=models.CASCADE)
# workshop = models.ForeignKey(Organization, verbose_name='生产车间', on_delete=models.CASCADE)
# process = models.ForeignKey(Process, verbose_name='关联大工序', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联子计划', on_delete=models.CASCADE)
material = models.ForeignKey(Material, verbose_name='关联物料', on_delete=models.CASCADE)
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
count = models.IntegerField('当前数量', default=0)
@ -36,7 +37,7 @@ class WProduct(CommonAModel):
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
class WProductForm(CommonAModel):
class WProductRecord(CommonAModel):
"""
记录表格
"""
@ -46,6 +47,6 @@ class WProductForm(CommonAModel):
class WProductFlow(BaseModel):
"""
产品流转日志
生产操作日志
"""
wproduct = models.ForeignKey(WProduct, verbose_name='产品', on_delete=models.CASCADE)
wproducts = models.JSONField('关联产品', default=list)

View File

@ -2,7 +2,7 @@ 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
from apps.mtm.models import Material, Step
from apps.mtm.serializers import MaterialSimpleSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress
@ -23,6 +23,8 @@ class PickSerializer(serializers.Serializer):
def create(self, validated_data):
picks = validated_data.pop('picks')
sp = validated_data['subproduction_plan']
if sp.state not in [1,2]:
raise serializers.ValidationError('该子计划状态错误')
if sp.is_picked:
raise serializers.ValidationError('该子计划已领料')
for i in picks:
@ -46,20 +48,21 @@ class PickSerializer(serializers.Serializer):
FIFODetail.objects.create(**i)
# 更新车间物料
wm, _ = WMaterial.objects.get_or_create(material=i['material'], batch=i['batch'], \
process=sp.process,defaults={
subproduction_plan=sp,defaults={
'material':i['material'],
'batch':i['batch'],
'process':sp.process,
'workshop':sp.workshop,
'subproduction_plan':sp,
'count':0
})
wm.count = wm.count + i['count']
wm.save()
# 更新子计划物料情况
spp = SubProductionProgress.objects.get(material=i['material'], subproduction_plan=sp, type=1)
spp.count_real = spp.count_real + i['count']
spp.count_pick = spp.count_pick + i['count']
spp.save()
sp.is_picked=True
sp.state = 3 #生产中
sp.state_date_real = timezone.now() #实际开工日期
sp.save()
# 更新库存
fifo.is_audited = True
@ -74,4 +77,8 @@ class WMaterialListSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
class Meta:
model = WMaterial
fields = '__all__'
fields = '__all__'
class DoFormInitSerializer(serializers.Serializer):
action = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all())

View File

@ -3,10 +3,11 @@ from rest_framework import urlpatterns
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from apps.wpm.views import WMaterialViewSet
from apps.wpm.views import WMaterialViewSet, WPlanViewSet
router = DefaultRouter()
router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
router.register('subplan', WPlanViewSet, basename='wplan')
urlpatterns = [
path('', include(router.urls)),
]

View File

@ -3,7 +3,8 @@ from rest_framework.generics import CreateAPIView, GenericAPIView
from rest_framework.mixins import ListModelMixin
from rest_framework.utils.field_mapping import get_relation_kwargs
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.pm.serializers import SubProductionPlanUpdateSerializer
from apps.pm.models import SubProductionPlan
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action
@ -12,6 +13,18 @@ from apps.wpm.models import WMaterial
from apps.wpm.serializers import PickSerializer, WMaterialListSerializer
from rest_framework.response import Response
# Create your views here.
class WPlanViewSet(ListModelMixin, GenericViewSet):
"""
车间生产计划
"""
perms_map = {'*': '*'}
queryset = SubProductionPlan.objects.select_related('process', 'workshop', 'subproduction', 'main_product').exclude(state=0)
search_fields = []
serializer_class = SubProductionPlanListSerializer
filterset_fields = ['production_plan', 'process', 'state', 'main_product', 'workshop']
ordering_fields = ['process__number']
ordering = ['process__number']
class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
"""
车间物料表
@ -19,7 +32,7 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
perms_map={'*':'*'}
queryset = WMaterial.objects.select_related('material').all()
serializer_class = WMaterialListSerializer
filterset_fields = ['material', 'process', 'workshop']
filterset_fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop']
ordering_fields = ['material__number']
ordering = ['material__number']

View File

@ -2,9 +2,8 @@ from django.db import models
import django.utils.timezone as timezone
from django.db.models.query import QuerySet
# 自定义软删除查询基类
class SoftDeletableQuerySetMixin(object):
'''
QuerySet for SoftDeletableModel. Instead of removing instance sets
@ -63,6 +62,24 @@ class BaseModel(models.Model):
class Meta:
abstract = True
def save(self, *args, **kwargs):
if self.pk:
# If self.pk is not None then it's an update.
cls = self.__class__
old = cls.objects.get(pk=self.pk)
# This will get the current model state since super().save() isn't called yet.
new = self # This gets the newly instantiated Mode object with the new values.
changed_fields = []
for field in cls._meta.get_fields():
field_name = field.name
try:
if getattr(old, field_name) != getattr(new, field_name):
changed_fields.append(field_name)
except Exception as ex: # Catch field does not exist exception
pass
kwargs['update_fields'] = changed_fields
super().save(*args, **kwargs)
class SoftModel(BaseModel):
"""
软删除基本表