车间物料表修改对应子计划
This commit is contained in:
parent
b6dca27688
commit
29a0a0d33a
|
@ -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) # 更新库存
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -5,3 +5,5 @@ class SamConfig(AppConfig):
|
|||
verbose_name = '生产计划管理'
|
||||
|
||||
|
||||
def ready(self):
|
||||
import apps.pm.signals
|
|
@ -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='实际消耗/产出数'),
|
||||
),
|
||||
]
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
@ -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']
|
||||
|
||||
|
|
|
@ -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',
|
||||
),
|
||||
]
|
|
@ -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)
|
|
@ -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())
|
|
@ -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)),
|
||||
]
|
||||
|
|
|
@ -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']
|
||||
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
软删除基本表
|
||||
|
|
Loading…
Reference in New Issue