车间操作重新梳理
This commit is contained in:
parent
b8495ee431
commit
bd179c20b1
|
@ -26,7 +26,7 @@ class MaterialDetailSerializer(serializers.ModelSerializer):
|
|||
class MaterialSimpleSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Material
|
||||
fields = ['id', 'name', 'number', 'unit','specification']
|
||||
fields = ['id', 'name', 'number', 'unit','specification', 'type']
|
||||
|
||||
class ProcessSerializer(serializers.ModelSerializer):
|
||||
instruction_ = FileSimpleSerializer(source='instruction', read_only=True)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.2.9 on 2021-11-19 02:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pm', '0013_alter_subproductionplan_subproduction'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='subproductionplan',
|
||||
name='number',
|
||||
field=models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='子计划编号'),
|
||||
),
|
||||
]
|
|
@ -44,6 +44,7 @@ class SubProductionPlan(CommonAModel):
|
|||
(SUBPLAN_STATE_WORKING, '生产中'),
|
||||
(SUBPLAN_STATE_DONE, '已完成')
|
||||
)
|
||||
number = models.CharField('子计划编号', max_length=50, unique=True, null=True, blank=True)
|
||||
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
|
||||
subproduction = models.ForeignKey(SubProduction, verbose_name='关联生产分解', on_delete=models.CASCADE, related_name='subplan_subprod')
|
||||
start_date = models.DateField('计划开工日期')
|
||||
|
|
|
@ -55,3 +55,8 @@ class PickNeedSerializer(serializers.Serializer):
|
|||
|
||||
class PlanDestorySerializer(serializers.Serializer):
|
||||
ids = serializers.ListField(child=serializers.IntegerField(), label='主计划ID列表')
|
||||
|
||||
class SubproductionPlanSimpleSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SubProductionPlan
|
||||
fields = ['id', 'number']
|
||||
|
|
|
@ -62,7 +62,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
|
|||
pass
|
||||
else:
|
||||
raise APIException('排产数量错误')
|
||||
instance = serializer.save(create_by=request.user, product=order.product, number='JH-'+ranstr(7))
|
||||
instance = serializer.save(create_by=request.user, product=order.product, number='JH'+ranstr(7))
|
||||
updateOrderPlanedCount(instance.order)
|
||||
return Response()
|
||||
|
||||
|
@ -83,13 +83,13 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
|
|||
if production_plan.is_planed:
|
||||
raise APIException('已生成子计划')
|
||||
subps = SubProduction.objects.filter(product=production_plan.product).order_by('process__number')
|
||||
for i in subps:
|
||||
for index, i in enumerate(subps):
|
||||
steps = Step.objects.filter(usedstep__subproduction=i, usedstep__subproduction__is_deleted=False,
|
||||
usedstep__is_deleted=False, is_deleted=False).values('id', 'number', 'name', 'usedstep__remark')
|
||||
instance = SubProductionPlan.objects.create(production_plan=production_plan, subproduction=i,
|
||||
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))
|
||||
steps = list(steps), number=production_plan.number + '-' + str(index+1))
|
||||
# 生成子计划物料需求/进度
|
||||
for m in SubprodctionMaterial.objects.filter(subproduction=i, is_deleted=False).order_by('sort'):
|
||||
spro = SubProductionProgress.objects.create(material=m.material, type=m.type,
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
# Generated by Django 3.2.9 on 2021-11-19 00:48
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pm', '0013_alter_subproductionplan_subproduction'),
|
||||
('qm', '0010_rename_m_state_testrecord_material'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='testrecord',
|
||||
name='is_testok_robot',
|
||||
field=models.BooleanField(default=True, verbose_name='自动判定的是否合格'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='testrecord',
|
||||
name='number',
|
||||
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='产品编号'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='testrecord',
|
||||
name='subproduction_plan',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionplan', verbose_name='关联的生产子计划'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='testrecorditem',
|
||||
name='is_testok_robot',
|
||||
field=models.BooleanField(blank=True, null=True, verbose_name='自动判定的是否合格'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,28 @@
|
|||
# Generated by Django 3.2.9 on 2021-11-19 00:48
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wpm', '0015_auto_20211117_2332'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='operation',
|
||||
name='wproducts',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='operation',
|
||||
name='is_submited',
|
||||
field=models.BooleanField(default=True, verbose_name='是否提交'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='wproduct',
|
||||
name='operation',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='current_operation', to='wpm.operation', verbose_name='关联操作'),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,49 @@
|
|||
# Generated by Django 3.2.9 on 2021-11-19 02:34
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('em', '0009_auto_20210916_1108'),
|
||||
('wpm', '0016_auto_20211119_0848'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='operationrecord',
|
||||
name='create_by',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='operationrecord',
|
||||
name='update_by',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='operationrecord',
|
||||
name='is_filled',
|
||||
field=models.BooleanField(default=True, verbose_name='是否填写'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='operation',
|
||||
name='is_submited',
|
||||
field=models.BooleanField(default=False, verbose_name='是否提交'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='OperationEquip',
|
||||
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='删除标记')),
|
||||
('remark', models.TextField(blank=True, null=True, verbose_name='备注')),
|
||||
('equip', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='em.equipment', verbose_name='生产设备')),
|
||||
('operation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='wpm.operation', verbose_name='关联操作')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
|
@ -9,6 +9,7 @@ from utils.model import SoftModel, BaseModel
|
|||
from simple_history.models import HistoricalRecords
|
||||
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm
|
||||
from django.core.validators import MinValueValidator
|
||||
from apps.em.models import Equipment
|
||||
class WMaterial(BaseModel):
|
||||
"""
|
||||
车间生产物料
|
||||
|
@ -44,17 +45,17 @@ 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)
|
||||
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
# operation = models.ForeignKey('wpm.operation', verbose_name='关联操作',
|
||||
# on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation')
|
||||
operation = models.ForeignKey('wpm.operation', verbose_name='关联操作',
|
||||
on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation')
|
||||
|
||||
class Operation(CommonADModel):
|
||||
"""
|
||||
生产操作
|
||||
"""
|
||||
wproducts = models.ManyToManyField(WProduct, verbose_name='关联半成品', through='wpm.operationwproduct')
|
||||
step = models.ForeignKey(Step, verbose_name='操作步骤', on_delete=models.CASCADE, null=True, blank=True)
|
||||
use_scrap = models.BooleanField('是否使用的边角料', default=False)
|
||||
remark = models.CharField('操作备注', max_length=200, null=True, blank=True)
|
||||
is_submited = models.BooleanField('是否提交', default=False)
|
||||
|
||||
class OperationWproduct(BaseModel):
|
||||
"""
|
||||
|
@ -82,13 +83,13 @@ class OperationMaterial(BaseModel):
|
|||
material = models.ForeignKey(Material, verbose_name='可能产出的副产品', on_delete=models.CASCADE, null=True, blank=True)
|
||||
count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)])
|
||||
|
||||
class OperationRecord(CommonAModel):
|
||||
class OperationRecord(BaseModel):
|
||||
"""
|
||||
记录表格
|
||||
"""
|
||||
form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE)
|
||||
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
|
||||
|
||||
is_filled = models.BooleanField('是否填写', default=True)
|
||||
|
||||
class OperationRecordItem(BaseModel):
|
||||
"""
|
||||
|
@ -102,3 +103,7 @@ class OperationRecordItem(BaseModel):
|
|||
sort = models.IntegerField('排序号', default=1)
|
||||
operation_record = models.ForeignKey(OperationRecord, verbose_name='关联的生产记录', on_delete=models.CASCADE)
|
||||
|
||||
class OperationEquip(BaseModel):
|
||||
operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE)
|
||||
equip = models.ForeignKey(Equipment, verbose_name='生产设备', on_delete=models.CASCADE)
|
||||
remark = models.TextField('备注', null=True, blank=True)
|
|
@ -8,9 +8,10 @@ from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer
|
|||
from apps.pm.models import SubProductionPlan, SubProductionProgress
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from apps.pm.serializers import SubproductionPlanSimpleSerializer
|
||||
from apps.qm.models import TestRecord, TestRecordItem
|
||||
from apps.system.serializers import UserSimpleSerializer
|
||||
from apps.wpm.models import Operation, WMaterial, WProduct, OperationRecord, OperationRecordItem
|
||||
from apps.wpm.models import Operation, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem
|
||||
from django.db import transaction
|
||||
|
||||
class PickHalfSerializer(serializers.Serializer):
|
||||
|
@ -130,20 +131,14 @@ class WProductListSerializer(serializers.ModelSerializer):
|
|||
fields = '__all__'
|
||||
|
||||
class OperationDetailSerializer(serializers.ModelSerializer):
|
||||
wproducts_ = serializers.SerializerMethodField()
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||||
step_ = StepSimpleSerializer(source='step', read_only=True)
|
||||
class Meta:
|
||||
model = Operation
|
||||
fields = '__all__'
|
||||
|
||||
def get_wproducts_(self, obj):
|
||||
return list(WProduct.objects.filter(id__in=obj.wproducts).values('id', 'number'))
|
||||
|
||||
class OperationListSerializer(serializers.ModelSerializer):
|
||||
create_by_ = UserSimpleSerializer(source='create_by', read_only=True)
|
||||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||||
step_ = StepSimpleSerializer(source='step', read_only=True)
|
||||
class Meta:
|
||||
model = Operation
|
||||
|
@ -231,6 +226,12 @@ class OperationRecordSerializer(serializers.ModelSerializer):
|
|||
model = OperationRecord
|
||||
fields = ['form', 'record_data']
|
||||
|
||||
class OperationWproductListSerializer(serializers.ModelSerializer):
|
||||
material_ = MaterialSimpleSerializer(source='material', read_only=True)
|
||||
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
|
||||
class Meta:
|
||||
model = OperationWproduct
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class OperationSubmitSerializer(serializers.Serializer):
|
||||
|
|
|
@ -3,12 +3,13 @@ from rest_framework import urlpatterns
|
|||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
|
||||
from apps.wpm.views import DoFormInit, DoFormSubmit, OperationViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet
|
||||
from apps.wpm.views import DoFormInit, DoFormSubmit, OperationViewSet, OperationWproductViewSet, WMaterialViewSet, WPlanViewSet, WProductViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register('wmaterial', WMaterialViewSet, basename='wmaterial')
|
||||
router.register('wproduct', WProductViewSet, basename='wproduct')
|
||||
router.register('operation', OperationViewSet, basename='operation')
|
||||
router.register('operation_wproduct', OperationWproductViewSet, basename='operation_wproduct')
|
||||
router.register('subplan', WPlanViewSet, basename='wplan')
|
||||
urlpatterns = [
|
||||
path('do/init/', DoFormInit.as_view()),
|
||||
|
|
|
@ -15,9 +15,9 @@ from apps.qm.models import TestRecordItem
|
|||
|
||||
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
|
||||
from rest_framework.decorators import action
|
||||
from apps.wpm.models import OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
|
||||
from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
|
||||
|
||||
from apps.wpm.serializers import OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer
|
||||
from apps.wpm.serializers import OperationWproductListSerializer, OperationCreateSerializer, OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer
|
||||
from rest_framework.response import Response
|
||||
from django.db import transaction
|
||||
from rest_framework import exceptions, serializers
|
||||
|
@ -67,7 +67,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
|||
wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']])
|
||||
wps.update(step=first_step, is_executed=False,
|
||||
act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None,
|
||||
subproduction_plan=sp, production_plan=sp.production_plan)
|
||||
subproduction_plan=sp, production_plan=sp.production_plan, update_by=request.user, update_time=timezone.now())
|
||||
return Response()
|
||||
|
||||
|
||||
|
@ -125,7 +125,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
|
|||
IProduct.objects.bulk_create(ips2)
|
||||
# 更新库存并修改半成品进行状态
|
||||
update_inm(fifo)
|
||||
wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse)
|
||||
wproducts.update(act_sate=WProduct.WPR_ACT_STATE_INM, warehouse=warehouse, update_by=request.user, update_time=timezone.now())
|
||||
|
||||
return Response()
|
||||
|
||||
|
@ -156,7 +156,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
|||
半成品
|
||||
"""
|
||||
perms_map={'*':'*'}
|
||||
queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False)
|
||||
queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False).exclude(operation=None)
|
||||
serializer_class = WProductListSerializer
|
||||
filterset_fields = ['step', 'subproduction_plan', 'material', 'production_plan', 'step__process', 'act_state']
|
||||
search_fields = ['number']
|
||||
|
@ -199,7 +199,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
|
|||
if obj.is_testok:
|
||||
wproduct.act_state = WProduct.WPR_ACT_STATE_OK
|
||||
if wproduct.number is None: # 产生半成品编号
|
||||
wproduct.number = 'WP-'+ranstr(7)
|
||||
wproduct.number = 'WP'+ranstr(7)
|
||||
wproduct.save()
|
||||
# 更新子计划状态
|
||||
# 更新子计划主产品数
|
||||
|
@ -266,7 +266,7 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen
|
|||
perms_map={'*':'*'}
|
||||
queryset = Operation.objects.select_related('step', 'material').all()
|
||||
serializer_class = OperationListSerializer
|
||||
filterset_fields = ['step', 'step__process']
|
||||
filterset_fields = ['step', 'step__process', 'is_submited']
|
||||
ordering_fields = ['id']
|
||||
ordering = ['-id']
|
||||
|
||||
|
@ -283,8 +283,56 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Gen
|
|||
serializer = OperationCreateSerializer(data=data, context={'request':self.request})
|
||||
serializer.is_valid(raise_exception=True)
|
||||
vdata = serializer.validated_data #校验之后的数据
|
||||
step = Step.objects.get(pk=vdata['step'])
|
||||
op = Operation()
|
||||
op.step = step
|
||||
op.is_submited = False
|
||||
op.save()
|
||||
# 创建操作所用半成品关联记录
|
||||
if 'wproducts' in vdata:
|
||||
owps = []
|
||||
for i in vdata['wproducts']:
|
||||
owp = {}
|
||||
wpd = WProduct.objects.get(pk=i)
|
||||
owp['operation'] = op
|
||||
owp['wproduct'] = wpd
|
||||
owp['number'] = wpd.number
|
||||
owp['material'] = wpd.material
|
||||
owp['subproduction_plan'] = wpd.subproduction_plan
|
||||
owp['production_plan'] = wpd.production_plan
|
||||
owps.append(OperationWproduct(**owp))
|
||||
OperationWproduct.objects.bulk_create(owps)
|
||||
# 查询需要填写的自定义表格
|
||||
forms = RecordForm.objects.filter(step=step, type=RecordForm.RF_TYPE_DO)
|
||||
for i in forms:
|
||||
opr = OperationRecord()
|
||||
opr.operation = op
|
||||
opr.form = i
|
||||
opr.is_filled = False
|
||||
opr.save()
|
||||
# 查询需要使用的生产设备
|
||||
equips = step.equipements
|
||||
for i in equips:
|
||||
ope = OperationEquip()
|
||||
ope.operation = op
|
||||
ope.equip = i
|
||||
ope.save()
|
||||
return Response()
|
||||
|
||||
|
||||
|
||||
|
||||
class OperationWproductViewSet(ListModelMixin, GenericViewSet):
|
||||
"""
|
||||
操作使用的半成品
|
||||
"""
|
||||
perms_map={'*':'*'}
|
||||
queryset = OperationWproduct.objects.select_related('subproduction_plan', 'material').all()
|
||||
serializer_class = OperationWproductListSerializer
|
||||
filterset_fields = ['material', 'subproduction_plan', 'operation']
|
||||
ordering_fields = ['id']
|
||||
ordering = ['-id']
|
||||
|
||||
class DoFormInit(CreateAPIView, GenericAPIView):
|
||||
perms_map={'*':'*'}
|
||||
serializer_class=OperationInitSerializer
|
||||
|
|
|
@ -2,6 +2,6 @@ import random
|
|||
import string
|
||||
|
||||
def ranstr(num):
|
||||
salt = ''.join(random.sample(string.ascii_letters + string.digits, num))
|
||||
salt = ''.join(random.sample(string.ascii_lowercase + string.digits, num))
|
||||
return salt
|
||||
ranstr(10)
|
Loading…
Reference in New Issue