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

This commit is contained in:
shilixia 2021-11-23 15:20:56 +08:00
commit a4c37d5255
32 changed files with 1867 additions and 495 deletions

View File

@ -15,4 +15,11 @@ export function getFileList(query) {
method: 'get',
params: query
})
}
}
export function upFile(data) {
return request({
url: '/file/',
method: 'post',
data
})
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-11-23 02:52
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0035_auto_20211117_1637'),
]
operations = [
migrations.AddField(
model_name='recordformfield',
name='draw_template',
field=models.CharField(blank=True, max_length=200, null=True, verbose_name='绘图模板'),
),
migrations.AlterField(
model_name='recordformfield',
name='field_type',
field=models.CharField(choices=[('string', '字符串'), ('int', '整型'), ('float', '浮点'), ('boolean', '布尔'), ('date', '日期'), ('time', '时间'), ('datetime', '日期时间'), ('radio', '单选'), ('checkbox', '多选'), ('select', '单选下拉'), ('selects', '多选下拉'), ('textarea', '文本域'), ('draw', '绘图')], max_length=50, verbose_name='类型'),
),
]

View File

@ -131,6 +131,7 @@ class RecordFormField(CommonAModel):
('select', '单选下拉'),
('selects', '多选下拉'),
('textarea', '文本域'),
('draw', '绘图')
)
high_rule_choices = (
(1, '小于'),
@ -161,6 +162,8 @@ class RecordFormField(CommonAModel):
is_hidden = models.BooleanField('是否隐藏', default=False)
parent = models.ForeignKey('self', verbose_name='', on_delete=models.CASCADE, null=True, blank=True)
draw_template = models.CharField('绘图模板', max_length=200, null=True, blank=True)
class Meta:
verbose_name = '记录表格字段'

View File

@ -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)
@ -209,6 +209,12 @@ class RecordFormDetailSerializer(serializers.ModelSerializer):
def get_form_fields(self, obj):
serializer = RecordFormFieldSerializer(instance=RecordFormField.objects.filter(form=obj, is_deleted=False), many=True)
vdata = serializer.data
if obj.type == RecordForm.RF_TYPE_TEST:
for i in vdata:
if i['need_judge']:
i['is_testok'] = False
i['is_teskok_robot'] = False
return serializer.data

View File

@ -0,0 +1,27 @@
from django_filters import rest_framework as filters
from apps.mtm.models import Material, Step
from apps.pm.models import SubProductionProgress
from apps.wpm.models import Operation, WProduct
from apps.wpm.services import WpmServies
class SubproductionProgressFilterSet(filters.FilterSet):
operation = filters.NumberFilter(method='filter_operation')
class Meta:
model = SubProductionProgress
fields = ['material', 'subproduction_plan', 'operation', 'type']
def filter_operation(self, queryset, name, value):
operation = Operation.objects.get(pk=value)
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
step = operation.step
if wproducts.exists():
subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts)
else:
subplans = WpmServies.get_subplans_queyset_from_step(step)
queryset = queryset.filter(subproduction_plan__in=subplans)
if step.type == Step.STEP_TYPE_NOM:
queryset = queryset.exclude(material__type=Material.MA_TYPE_HALFGOOD)
return queryset

View File

@ -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='子计划编号'),
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-11-22 07:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pm', '0014_subproductionplan_number'),
]
operations = [
migrations.AddField(
model_name='subproductionplan',
name='main_count_ok',
field=models.IntegerField(default=0, verbose_name='合格数'),
),
migrations.AddField(
model_name='subproductionprogress',
name='count_ok',
field=models.IntegerField(default=0, verbose_name='合格数量'),
),
]

View File

@ -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,6 +56,7 @@ class SubProductionPlan(CommonAModel):
main_product = models.ForeignKey(Material, verbose_name='主要产品', on_delete=models.CASCADE, null=True, blank=True)
main_count = models.IntegerField('应产出数', default=0)
main_count_real = models.IntegerField('实际产出数', default=0)
main_count_ok = models.IntegerField('合格数', default=0)
steps = models.JSONField('工艺步骤', default=list)
@ -79,3 +81,4 @@ class SubProductionProgress(BaseModel):
count = models.IntegerField('应出入数')
count_pick = models.IntegerField('实际领用数', default=0)
count_real = models.IntegerField('实际消耗/产出数', default=0)
count_ok = models.IntegerField('合格数量', default=0)

View File

@ -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']

View File

@ -1,4 +1,4 @@
from apps.pm.views import ProductionPlanViewSet, ResourceViewSet, SubProductionPlanViewSet
from apps.pm.views import ProductionPlanViewSet, ResourceViewSet, SubProductionPlanViewSet, SubProductionProgressViewSet
from django.db.models import base
from rest_framework import urlpatterns
from django.urls import path, include
@ -7,6 +7,7 @@ from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('production_plan', ProductionPlanViewSet, basename='production_plan')
router.register('subproduction_plan', SubProductionPlanViewSet, basename='subproduction_plan')
router.register('subproduction_progress', SubProductionProgressViewSet, basename='subproduction_progress')
router.register('resource', ResourceViewSet, basename='resource')
urlpatterns = [
path('', include(router.urls)),

View File

@ -1,4 +1,5 @@
from datetime import timezone
from typing import List
from django.db import transaction
from rest_framework import serializers
from rest_framework.views import APIView
@ -7,6 +8,7 @@ from apps.em.serializers import EquipmentSerializer
from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
from apps.pm.filters import SubproductionProgressFilterSet
from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin
@ -62,12 +64,12 @@ 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()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PlanDestorySerializer)
def destory(self, request, pk=None):
def deletes(self, request, pk=None):
"""
批量物理删除
"""
@ -83,13 +85,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,
@ -178,6 +180,17 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
have = MaterialBatchSerializer(instance=objs, many=True).data
return Response({'need':need, 'have':have})
class SubProductionProgressViewSet(ListModelMixin, GenericViewSet):
"""
生产进度
"""
perms_map = {'*': '*'}
queryset = SubProductionProgress.objects.select_related('material', 'subproduction_plan')
search_fields = []
serializer_class = SubProductionProgressSerializer
filterset_class = SubproductionProgressFilterSet
ordering_fields = ['id']
ordering = ['id']
class ResourceViewSet(GenericViewSet):

View File

@ -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='自动判定的是否合格'),
),
]

View File

@ -49,8 +49,11 @@ class TestRecord(CommonAModel):
"""
form = models.ForeignKey('mtm.recordform', verbose_name='所用表格', on_delete=models.CASCADE)
is_testok = models.BooleanField('是否合格', default=True)
is_testok_robot = models.BooleanField('自动判定的是否合格', default=True)
number = models.CharField('产品编号', null=True, blank=True, max_length=50)
wproduct = models.ForeignKey('wpm.wproduct', verbose_name='关联的动态产品', on_delete=models.CASCADE, null=True, blank=True)
material = models.ForeignKey('mtm.material', verbose_name='关联的物料状态', on_delete=models.CASCADE, null=True, blank=True)
subproduction_plan = models.ForeignKey('pm.subproductionplan', verbose_name='关联的生产子计划', on_delete=models.CASCADE, null=True, blank=True)
fifo_item = models.ForeignKey('inm.fifoitem', verbose_name='关联的出入库批次', on_delete=models.CASCADE, null=True, blank=True)
remark = models.TextField('备注', default='')
@ -66,5 +69,6 @@ class TestRecordItem(BaseModel):
field_value = models.JSONField('录入值', default=dict, blank=True)
need_judge = models.BooleanField('是否需要判定', default=False)
sort = models.IntegerField('排序号', default=1)
is_testok = models.BooleanField('是否合格', null=True, blank=True)
is_testok = models.BooleanField('是否合格', null=True, blank=True)
is_testok_robot = models.BooleanField('自动判定的是否合格', null=True, blank=True)
test_record = models.ForeignKey(TestRecord, verbose_name='关联的检测记录', on_delete=models.CASCADE, related_name='item_test_record')

View File

@ -0,0 +1,23 @@
from django_filters import rest_framework as filters
from apps.mtm.models import Material, Step
from apps.wpm.services import WpmServies
from .models import Operation, WMaterial, WProduct
class WMaterialFilterSet(filters.FilterSet):
operation = filters.NumberFilter(method='filter_operation')
class Meta:
model = WMaterial
fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop', 'operation']
def filter_operation(self, queryset, name, value):
operation = Operation.objects.get(pk=value)
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
step = operation.step
if wproducts.exists():
subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts)
else:
subplans = WpmServies.get_subplans_queyset_from_step(step)
queryset = queryset.filter(subproduction_plan__in=subplans).exclude(material__type=Material.MA_TYPE_HALFGOOD)
return queryset

View File

@ -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='关联操作'),
),
]

View File

@ -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,
},
),
]

View File

@ -0,0 +1,29 @@
# Generated by Django 3.2.9 on 2021-11-19 05:40
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0017_auto_20211119_1034'),
]
operations = [
migrations.AlterField(
model_name='operationequip',
name='operation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='oe_operation', to='wpm.operation', verbose_name='关联操作'),
),
migrations.AlterField(
model_name='operationrecord',
name='operation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='or_operation', to='wpm.operation', verbose_name='关联的生产操作'),
),
migrations.AlterField(
model_name='operationwproduct',
name='operation',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ow_operation', to='wpm.operation', verbose_name='关联操作'),
),
]

View File

@ -0,0 +1,46 @@
# Generated by Django 3.2.9 on 2021-11-22 03:10
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('mtm', '0035_auto_20211117_1637'),
('pm', '0014_subproductionplan_number'),
('wpm', '0018_auto_20211119_1340'),
]
operations = [
migrations.AddField(
model_name='operationmaterial',
name='batch',
field=models.CharField(blank=True, max_length=100, null=True, verbose_name='批次号'),
),
migrations.AddField(
model_name='operationmaterial',
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='operationmaterial',
name='subproduction_progress',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='pm.subproductionprogress', verbose_name='关联的生产进度'),
),
migrations.AlterField(
model_name='operationmaterial',
name='material',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='可能产出的产品'),
),
migrations.AlterField(
model_name='operationmaterial',
name='type',
field=models.IntegerField(choices=[(1, '输入物料'), (2, '输出物料'), (3, '工具工装')], default=0, verbose_name='类型'),
),
migrations.AlterField(
model_name='wproduct',
name='subproduction_plan',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='wproduct_subplan', to='pm.subproductionplan', verbose_name='当前子生产计划'),
),
]

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.9 on 2021-11-22 07:56
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0019_auto_20211122_1110'),
]
operations = [
migrations.AlterField(
model_name='operationwproduct',
name='wproduct',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ow_wproduct', to='wpm.wproduct', verbose_name='关联半成品'),
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 3.2.9 on 2021-11-23 01:45
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wpm', '0020_alter_operationwproduct_wproduct'),
]
operations = [
migrations.RemoveField(
model_name='operationwproduct',
name='production_plan',
),
migrations.RemoveField(
model_name='wproduct',
name='production_plan',
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-11-23 06:25
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0021_auto_20211123_0945'),
]
operations = [
migrations.RemoveField(
model_name='wproduct',
name='parent',
),
migrations.AddField(
model_name='wproduct',
name='child',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='wpm.wproduct'),
),
]

View File

@ -3,12 +3,13 @@ from django.db.models.base import Model
import django.utils.timezone as timezone
from django.db.models.query import QuerySet
from apps.inm.models import WareHouse
from apps.pm.models import ProductionPlan, SubProductionPlan
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
from apps.pm.models import ProductionPlan, SubProductionPlan, SubProductionProgress
from apps.system.models import CommonADModel, CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm
from apps.mtm.models import Material, Process, RecordFormField, Step, RecordForm, SubprodctionMaterial
from django.core.validators import MinValueValidator
from apps.em.models import Equipment
class WMaterial(BaseModel):
"""
车间生产物料
@ -39,54 +40,56 @@ class WProduct(CommonAModel):
act_state = models.IntegerField('进行状态', default=0, choices=act_state_choices)
is_executed = models.BooleanField('子工序是否已执行', default=False)
is_hidden = models.BooleanField('是否隐藏', default=False)
parent = models.JSONField('', default=list, blank=True)
child = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan')
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')
class Operation(CommonAModel):
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):
"""
生产操作半成品关联表
"""
operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE)
wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE)
operation = models.ForeignKey(Operation, verbose_name='关联操作', on_delete=models.CASCADE, related_name='ow_operation')
wproduct = models.ForeignKey(WProduct, verbose_name='关联半成品', on_delete=models.CASCADE, related_name='ow_wproduct')
number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, 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)
class OperationMaterial(BaseModel):
"""
生产操作物料消耗产出表
"""
type_choices=(
(1, '消耗'),
(2, '产出')
)
type = models.IntegerField('类型', default=0, choices=type_choices)
type = models.IntegerField('类型', default=0, choices=SubprodctionMaterial.type_choices)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
wmaterial = models.ForeignKey(WMaterial, 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)
count = models.IntegerField('消耗或产出数量', validators=[MinValueValidator(0)])
class OperationRecord(CommonAModel):
wmaterial = models.ForeignKey(WMaterial, verbose_name='关联的车间物料', on_delete=models.CASCADE, null=True, blank=True)
subproduction_progress = models.ForeignKey(SubProductionProgress, verbose_name='关联的生产进度', on_delete=models.CASCADE, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='关联的子计划', on_delete=models.CASCADE, null=True, blank=True)
batch = models.CharField('批次号', max_length=100, null=True, blank=True)
class OperationRecord(BaseModel):
"""
记录表格
"""
form = models.ForeignKey(RecordForm, verbose_name='所用的生产记录表格', on_delete=models.CASCADE)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE)
operation = models.ForeignKey(Operation, verbose_name='关联的生产操作', on_delete=models.CASCADE, related_name='or_operation')
is_filled = models.BooleanField('是否填写', default=True)
class OperationRecordItem(BaseModel):
"""
@ -100,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, related_name='oe_operation')
equip = models.ForeignKey(Equipment, verbose_name='生产设备', on_delete=models.CASCADE)
remark = models.TextField('备注', null=True, blank=True)

View File

@ -1,19 +1,22 @@
from rest_framework import serializers, exceptions
from rest_framework.serializers import ModelSerializer
from apps.em.serializers import EquipmentSimpleSerializer
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, MaterialBatch, WareHouse
from apps.inm.signals import update_inm
from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial
from apps.mtm.serializers import MaterialSimpleSerializer, StepSimpleSerializer
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial
from apps.mtm.serializers import MaterialSimpleSerializer, RecordFormSimpleSerializer, 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, OperationEquip, OperationMaterial, OperationWproduct, WMaterial, WProduct, OperationRecord, OperationRecordItem
from django.db import transaction
class PickHalfSerializer(serializers.Serializer):
id = serializers.PrimaryKeyRelatedField(queryset=SubProductionProgress.objects.all(), label='子计划进度ID')
wproducts = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all(), label='半成品ID'),
required=False) # 从半成品表里直接修改状态
class PickDetailSerializer(serializers.Serializer):
@ -129,25 +132,68 @@ 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)
wproduct_count = serializers.SerializerMethodField()
equip_count = serializers.SerializerMethodField()
record_count = serializers.SerializerMethodField()
class Meta:
model = Operation
fields = '__all__'
def get_wproduct_count(self, obj):
return obj.ow_operation.count()
def get_equip_count(self, obj):
return obj.oe_operation.count()
def get_record_count(self, obj):
return obj.or_operation.count()
class OperationCreateSerializer(serializers.Serializer):
"""
操作创建
"""
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
# subproduction_plan = serializers.PrimaryKeyRelatedField(queryset=SubProductionPlan.objects.all(), label="子计划ID", required=False)
wproducts = serializers.ListField(child=
serializers.PrimaryKeyRelatedField(queryset=WProduct.objects.all()), label="半成品ID列表", required=False)
def validate(self, data):
# subproduction_plan = data['subproduction_plan']
step = data['step']
# stepIds=[i['id'] for i in subproduction_plan.steps]
# if step.id not in stepIds:
# raise exceptions.ValidationError('请选择正确的子工序操作')
if 'wproducts' in data and data['wproducts']:
if step.type == Step.STEP_TYPE_DIV:
raise exceptions.ValidationError(_('不可进行此操作'))
for i in data['wproducts']:
if i.is_executed:
raise exceptions.ValidationError('不可进行操作')
# if i.subproduction_plan != subproduction_plan:
# raise exceptions.ValidationError('半成品所属子计划不一致')
if i.step != step:
raise exceptions.ValidationError('半成品所属子工序不一致')
else:
if step.type != Step.STEP_TYPE_DIV:
raise exceptions.ValidationError(_('请选择半成品进行操作'))
return data
class OperationUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Operation
fields =['use_scrap', 'remark']
class OperationInitSerializer(serializers.Serializer):
step = serializers.PrimaryKeyRelatedField(queryset=Step.objects.all(), label="子工序ID")
@ -193,12 +239,24 @@ class OperationRecordItemSerializer(serializers.ModelSerializer):
model = OperationRecordItem
fields = ['form_field', 'field_value']
class OperationRecordSubmitSerializer(serializers.ModelSerializer):
record_data = OperationRecordItemSerializer(many=True)
class Meta:
model = OperationRecord
fields = ['record_data']
class OperationRecordSerializer(serializers.ModelSerializer):
record_data = OperationRecordItemSerializer(many=True)
class Meta:
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):
@ -237,6 +295,66 @@ class WplanPutInSerializer(serializers.Serializer):
class WproductPutInSerializer(serializers.Serializer):
warehouse = serializers.PrimaryKeyRelatedField(queryset=WareHouse.objects.all(), label="仓库ID")
remark = serializers.CharField(label="入库备注", required =False)
class OperationEquipListSerializer(serializers.Serializer):
equip_ = EquipmentSimpleSerializer(source='equip', read_only=True)
class Meta:
model = OperationEquip
fields = '__all__'
class OperationEquipUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = OperationEquip
fields = ['remark']
class OperationRecordListSerializer(serializers.ModelSerializer):
form_ = RecordFormSimpleSerializer(source='form', read_only=True)
class Meta:
model = OperationRecord
fields = '__all__'
class OperationMaterialListSerializer(serializers.ModelSerializer):
material_ = MaterialSimpleSerializer(source='material', read_only=True)
subproduction_plan_ = SubproductionPlanSimpleSerializer(source='subproduction_plan', read_only=True)
class Meta:
model = OperationMaterial
fields = '__all__'
class OperationMaterialCreate1Serailizer(serializers.ModelSerializer):
wmaterial = serializers.PrimaryKeyRelatedField(required=True, queryset=WMaterial.objects.all())
class Meta:
model = OperationMaterial
fields = ['operation', 'wmaterial', 'count']
def create(self, validated_data):
wmaterial = validated_data['wmaterial']
validated_data['material'] = wmaterial.material
validated_data['subproduction_plan'] = wmaterial.subproduction_plan
validated_data['batch'] = wmaterial.batch
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_IN
return super().create(validated_data)
class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
subproduction_progress = serializers.PrimaryKeyRelatedField(required=True, queryset=SubProductionProgress.objects.all())
class Meta:
model = OperationMaterial
fields = ['operation', 'subproduction_progress', 'count']
def create(self, validated_data):
subproduction_progress = validated_data['subproduction_progress']
validated_data['material'] = subproduction_progress.material
validated_data['subproduction_plan'] = subproduction_progress.subproduction_plan
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_OUT
return super().create(validated_data)
class OperationMaterialCreate3Serializer(serializers.ModelSerializer):
material = serializers.PrimaryKeyRelatedField(required=True, queryset=Material.objects.all())
class Meta:
model = OperationMaterial
fields = ['operation', 'material']
def create(self, validated_data):
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_TOOL
return super().create(validated_data)

View File

@ -1,5 +1,7 @@
from typing import List
from apps.pm.models import SubProductionPlan
from apps.mtm.models import Step
from apps.mtm.models import Step, SubprodctionMaterial
from apps.wpm.models import WProduct
class WpmServies(object):
@classmethod
@ -12,4 +14,21 @@ class WpmServies(object):
if pindex + 1 < len(stepIds):
return Step.objects.get(pk=stepIds[pindex+1]), True
else:
return nowstep, False
return nowstep, False
@classmethod
def get_subplans_queryset_from_wproducts(cls, wproducts:List):
"""
通过半成品列表获取所属子计划
"""
splans = SubProductionPlan.objects.filter(is_deleted=False, wproduct_subplan__in=wproducts)
return splans
@classmethod
def get_subplans_queyset_from_step(cls, step:Step):
"""
通过当前操作获取所有正在进行的子计划
"""
splans = SubProductionPlan.objects.filter(is_deleted=False,
subproduction__usedstep_subproduction__step=step, state=SubProductionPlan.SUBPLAN_STATE_WORKING)
return splans

View File

@ -3,12 +3,18 @@ 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, OperationEquipViewSet, OperationMaterialInputViewSet, OperationMaterialOutputViewSet, OperationMaterialToolViewSet, OperationRecordViewSet, 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('operation_equip', OperationEquipViewSet, basename='operation_equip')
router.register('operation_record', OperationRecordViewSet, basename='operation_record')
router.register('operation_input', OperationMaterialInputViewSet, basename='operation_input')
router.register('operation_output', OperationMaterialOutputViewSet, basename='operation_output')
router.register('operation_tool', OperationMaterialToolViewSet, basename='operation_tool')
router.register('subplan', WPlanViewSet, basename='wplan')
urlpatterns = [
path('do/init/', DoFormInit.as_view()),

View File

@ -1,23 +1,24 @@
from django.shortcuts import render
from rest_framework.generics import CreateAPIView, GenericAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.mixins import CreateModelMixin, DestroyModelMixin, ListModelMixin, RetrieveModelMixin, UpdateModelMixin
from rest_framework.utils import serializer_helpers
from rest_framework.utils.field_mapping import get_relation_kwargs
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet, ModelViewSet
from apps.inm.models import FIFO, FIFOItem, FIFOItemProduct, IProduct, WareHouse
from apps.inm.signals import update_inm
from apps.mtm.models import Material, RecordForm, Step, SubprodctionMaterial, TechDoc
from apps.mtm.models import Material, RecordForm, RecordFormField, Step, SubprodctionMaterial, TechDoc
from apps.mtm.serializers import RecordFormDetailSerializer, SubprodctionMaterialListSerializer, TechDocListSerializer
from apps.pm.models import SubProductionPlan, SubProductionProgress
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer
from apps.pm.serializers import SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
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.filters import WMaterialFilterSet
from apps.wpm.models import OperationEquip, OperationWproduct, WMaterial, WProduct, Operation, OperationMaterial, OperationRecord, OperationRecordItem
from apps.wpm.serializers import OperationDetailSerializer, OperationListSerializer, PickHalfSerializer, PickSerializer, OperationInitSerializer, OperationSubmitSerializer, WMaterialListSerializer, WProductListSerializer, WplanPutInSerializer, WpmTestRecordCreateSerializer, WproductPutInSerializer
from apps.wpm.serializers import OperationEquipListSerializer, OperationEquipUpdateSerializer, OperationMaterialCreate1Serailizer, OperationMaterialCreate2Serailizer, OperationMaterialCreate3Serializer, OperationMaterialListSerializer, OperationRecordListSerializer, OperationRecordSubmitSerializer, OperationUpdateSerializer, 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
@ -25,6 +26,7 @@ from rest_framework import exceptions, serializers
from apps.wpm.services import WpmServies
from django.utils import timezone
from utils.tools import ranstr
from rest_framework import status
# Create your views here.
class WPlanViewSet(ListModelMixin, GenericViewSet):
"""
@ -49,19 +51,25 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
"""
领半成品
"""
mIds = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN,
material__type=Material.MA_TYPE_HALFGOOD).values_list('material', flat=True)
queyset = WProduct.objects.filter(is_hidden=False, material__in=mIds, act_state=WProduct.WPR_ACT_STATE_OK)
return Response(WProductListSerializer(instance=queyset, many=True).data)
spps = SubProductionProgress.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN,
material__type=Material.MA_TYPE_HALFGOOD, subproduction_plan=sp).select_related('material')
return Response(SubProductionProgressSerializer(instance=spps, many=True).data)
elif request.method=='POST':
serializer= PickHalfSerializer(data=request.data)
serializer= PickHalfSerializer(data=request.data, many=True)
serializer.is_valid(raise_exception=True)
vdata = serializer.data
wps = WProduct.objects.filter(pk__in=[x for x in vdata['wproducts']])
first_step = Step.objects.get(pk=sp.steps[0].id)
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)
first_step = Step.objects.get(pk=sp.steps[0]['id'])
for i in vdata:
if 'wproducts' in i and len(i['wproducts'])>0:
spp = SubProductionProgress.objects.get(pk=i['id'])
spp.count_pick = spp.count_pick + len(i['wproducts'])
if spp.count_pick > spp.count:
raise exceptions.APIException('超过计划数')
spp.save()
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, update_by=request.user, update_time=timezone.now())
return Response()
@ -76,7 +84,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
vdata = serializer.data
subplan = self.get_object()
material = subplan.main_product
batch = subplan.production_plan.number
batch = subplan.number
warehouse = WareHouse.objects.get(id=vdata['warehouse'])
wproducts = WProduct.objects.filter(subproduction_plan=subplan,
act_state=WProduct.WPR_ACT_STATE_OK, material=material, is_deleted=False)
@ -119,7 +127,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()
@ -131,7 +139,7 @@ class WMaterialViewSet(CreateUpdateModelAMixin, ListModelMixin, GenericViewSet):
perms_map={'*':'*'}
queryset = WMaterial.objects.select_related('material').all()
serializer_class = WMaterialListSerializer
filterset_fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop']
filterset_class = WMaterialFilterSet
ordering_fields = ['material__number']
ordering = ['material__number']
@ -150,9 +158,9 @@ 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, operation=None)
serializer_class = WProductListSerializer
filterset_fields = ['step', 'subproduction_plan', 'material', 'production_plan', 'step__process', 'act_state']
filterset_fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state']
search_fields = ['number']
ordering_fields = ['id']
ordering = ['id']
@ -193,13 +201,13 @@ 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()
# 更新子计划状态
# 更新子计划主产品数
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题
instance.count_ok = instance.count_ok + 1 # 这个地方可能会有问题
instance.save()
else:# 如果不合格
pass
@ -220,7 +228,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
if wproduct.act_state != WProduct.WPR_ACT_STATE_OK:
raise exceptions.APIException('半成品不可入库')
material = wproduct.material
batch = wproduct.production_plan.number
batch = wproduct.subproduction_plan.number
# 创建入库记录
remark = vdata.get('remark', '')
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
@ -253,22 +261,353 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
wproduct.save()
return Response()
class OperationViewSet(ListModelMixin, RetrieveModelMixin, GenericViewSet):
class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin, GenericViewSet):
"""
生产操作记录
"""
perms_map={'*':'*'}
queryset = Operation.objects.select_related('step', 'material').all()
queryset = Operation.objects.select_related('step').prefetch_related('ow_operation', 'oe_operation', 'or_operation').all()
serializer_class = OperationListSerializer
filterset_fields = ['step', 'step__process']
filterset_fields = ['step', 'step__process', 'is_submited']
ordering_fields = ['id']
ordering = ['-id']
def get_queryset(self):
return self.queryset.filter(create_by=self.request.user)
def get_serializer_class(self):
if self.action == 'retrieve':
return OperationDetailSerializer
elif self.action == 'create':
return OperationCreateSerializer
elif self.action == 'update':
return OperationUpdateSerializer
return super().get_serializer_class()
def update(self, request, *args, **kwargs):
instance = self.get_object()
if instance.is_submited:
raise exceptions.APIException('该操作已提交')
return super().update(request, *args, **kwargs)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.is_submited:
raise exceptions.APIException('该操作已提交')
self.perform_destroy(instance)
return Response(status=status.HTTP_204_NO_CONTENT)
@transaction.atomic
def create(self, request, *args, **kwargs):
data = request.data
serializer = OperationCreateSerializer(data=data, context={'request':self.request})
serializer.is_valid(raise_exception=True)
vdata = serializer.validated_data #校验之后的数据
step = vdata['step']
op = Operation()
op.step = step
op.is_submited = False
op.create_by = request.user
op.save()
splans = []
# 创建操作所用半成品关联记录
if 'wproducts' in vdata:
owps = []
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts'])
for wpd in vdata['wproducts']:
owp = {}
owp['operation'] = op
owp['wproduct'] = wpd
owp['number'] = wpd.number
owp['material'] = wpd.material
owp['subproduction_plan'] = wpd.subproduction_plan
owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps)
else:
splans = WpmServies.get_subplans_queryset_from_wproducts(vdata['wproducts'])
# 查询需要填写的自定义表格
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()
# 查询需要使用的生产设备
for i in step.equipments.all():
ope = OperationEquip()
ope.operation = op
ope.equip = i
ope.save()
# 查询所需的工具工装
for i in SubprodctionMaterial.objects.filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL,
subproduction__subplan_subprod__in = splans, is_deleted=False).distinct():
opm = OperationMaterial()
opm.operation = op
opm.material = i.material
opm.type = SubprodctionMaterial.SUB_MA_TYPE_TOOL
opm.save()
return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
@transaction.atomic
def submit(self, request, pk=None):
"""
提交车间操作重要
"""
op = self.get_object()
step = op.step
# 检查自定义表单填写
if OperationRecord.objects.filter(operation=op, is_filled=False).exists():
raise exceptions.APIException('存在自定义表单未填写')
# 更新物料消耗进度
for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_IN):
# 更新车间物料
i_wmat = i.wmaterial
i_wmat.count = i_wmat.count- i.count
i_wmat.save()
# 更新子计划物料消耗情况
spp = SubProductionProgress.objects.get(subproduction_plan=i_wmat.subproduction_plan,
material=i_wmat.material)
spp.count_real = spp.count_real + i.count
spp.save()
# 更新产出
for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT):
if not i.subproduction_progress.is_main:
# 更新车间物料产出情况
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i.subproduction_plan, material=i.material)
ins.count = ins.count + i.count
ins.save()
# 更新子计划物料产出情况
spp = i.subproduction_progress
spp.count_real = spp.count_real + i.count
spp.save()
# 更新动态产品表
if step.type == Step.STEP_TYPE_NOM:
for i in OperationWproduct.objects.filter(operation=op):
wp = i.wproduct
wsp = i.subproduction_plan
# 获取下一步子工序
newstep, hasNext = WpmServies.get_next_step(wsp, step)
wp.step = newstep
wp.pre_step = step
if hasNext:
wp.is_executed= False
else:
wp.is_executed = True
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
wp.material = wsp.main_product
# 更新子计划进度
instance = SubProductionProgress.objects.get(subproduction_plan=wsp,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save()
wp.operation = None
wp.save()
elif step.type == Step.STEP_TYPE_DIV:
# 更新物料产出情况
for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT):
if i.subproduction_progress.is_main:
newstep, _ = WpmServies.get_next_step(i.subproduction_plan, step)
wpr = dict(material=i.material, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
subproduction_plan=i.subproduction_plan)
for x in range(i.count):
WProduct.objects.create(**wpr)
elif step.type == Step.STEP_TYPE_COMB:
# 隐藏原半成品
ows = OperationWproduct.objects.filter(operation=op)
if i.subproduction_progress.is_main:
newstep, hasNext = WpmServies.get_next_step(i.subproduction_plan, step)
wproduct = WProduct()
wproduct.material = i.material
wproduct.step = newstep
wproduct.subproduction_plan = i.subproduction_plan
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
# 更新子计划进度
instance = SubProductionProgress.objects.get(subproduction_plan=i.subproduction_plan,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save()
wproduct.save()
ows.update(is_hidden=True, child=wproduct)
op.is_submited = True
op.save()
return Response()
class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, 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']
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
wp = instance.wproduct
wp.operation = None
wp.save()
return Response()
class OperationEquipViewSet(ListModelMixin, DestroyModelMixin, UpdateModelMixin, GenericViewSet):
"""
操作使用的设备
"""
perms_map={'*':'*'}
queryset = OperationEquip.objects.select_related('operation', 'equip').all()
serializer_class = OperationEquipListSerializer
filterset_fields = ['operation', 'equip']
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'update':
return OperationEquipUpdateSerializer
return super().get_serializer_class()
def update(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
return super().update(request, *args, **kwargs)
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
return Response()
class OperationRecordViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
"""
操作使用的自定义表格
"""
perms_map={'*':'*'}
queryset = OperationRecord.objects.select_related('operation', 'form').all()
serializer_class = OperationRecordListSerializer
filterset_fields = ['operation', 'form']
ordering_fields = ['id']
ordering = ['-id']
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=OperationRecordSubmitSerializer)
def submit(self, request, pk=None):
serializer = OperationRecordSubmitSerializer(data=request.data, context={'request':self.request})
serializer.is_valid(raise_exception=True)
vdata = serializer.data
opr = self.get_object()
wrds = []
for m in vdata['record_data']: # 保存记录详情
form_field = RecordFormField.objects.get(pk=m['form_field'])
m['form_field'] = form_field
m['field_name'] = form_field.field_name
m['field_key'] = form_field.field_key
m['field_type'] = form_field.field_type
m['field_value'] = m['field_value']
m['sort'] = form_field.sort
m['operation_record'] = opr
wrds.append(OperationRecordItem(**m))
OperationRecordItem.objects.bulk_create(wrds)
opr.is_filled = True
opr.save()
return Response()
class OperationMaterialInputViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
"""
消耗物料
"""
perms_map={'*':'*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_IN)
serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'create':
return OperationMaterialCreate1Serailizer
return super().get_serializer_class()
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
return Response()
class OperationMaterialOutputViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
"""
产出物料
"""
perms_map={'*':'*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'create':
return OperationMaterialCreate2Serailizer
return super().get_serializer_class()
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
return Response()
class OperationMaterialToolViewSet(ListModelMixin, CreateModelMixin, DestroyModelMixin, GenericViewSet):
"""
工具工装
"""
perms_map={'*':'*'}
queryset = OperationMaterial.objects.select_related('operation', 'subproduction_plan').filter(type=SubprodctionMaterial.SUB_MA_TYPE_TOOL)
serializer_class = OperationMaterialListSerializer
filterset_fields = ['operation', 'subproduction_plan']
ordering_fields = ['id']
ordering = ['-id']
def get_serializer_class(self):
if self.action == 'create':
return OperationMaterialCreate3Serializer
return super().get_serializer_class()
@transaction.atomic()
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.operation.is_submited:
raise exceptions.APIException('该操作已提交')
instance.delete()
return Response()
class DoFormInit(CreateAPIView, GenericAPIView):
perms_map={'*':'*'}
serializer_class=OperationInitSerializer
@ -368,7 +707,6 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
owp['number'] = wp.number
owp['material'] = wp.material
owp['subproduction_plan'] = wp.subproduction_plan
owp['production_plan'] = wp.production_plan
owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps)
@ -398,8 +736,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
wpr = dict(material=ma, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
subproduction_plan=i['subproduction_plan'],
production_plan=i['subproduction_plan'].production_plan)
subproduction_plan=i['subproduction_plan'])
for x in range(i['count_output']):
WProduct.objects.create(**wpr)
else:
@ -428,7 +765,6 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wproduct.material = vdata['subproduction_plan'].main_product
wproduct.step = 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

View File

@ -1,5 +1,5 @@
celery==5.1.2
Django==3.2.6
Django==3.2.9
django-celery-beat==2.2.1
django-cors-headers==3.7.0
django-filter==2.4.0

View File

@ -26,7 +26,7 @@ from rest_framework.documentation import include_docs_urls
from rest_framework_simplejwt.views import (TokenObtainPairView,
TokenRefreshView)
from django.views.generic import TemplateView
from utils.view import GenSignature
from utils.view import GenSignature, UpdateDevelop
router = routers.DefaultRouter()
router.register('', FileViewSet, basename="file")
@ -72,6 +72,7 @@ urlpatterns = [
# 工具
path('api/utils/signature/', GenSignature.as_view()),
path('api/utils/develop/', UpdateDevelop.as_view()),
# 前端页面入口
path('',TemplateView.as_view(template_name="index.html"))

View File

@ -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)

View File

@ -49,3 +49,22 @@ class GenSignature(APIView):
image[i][j][0],image[i][j][1],image[i][j][2] = 0,0,0
cv2.imwrite(path,image)
return Response(request.data, status=status.HTTP_200_OK)
class UpdateDevelop(APIView):
"""
更新开发服务器
"""
authentication_classes = ()
permission_classes = ()
def post(self, request, *args, **kwargs):
import os
# 更新后端
os.chdir('/home/hberp')
ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git develop')
# 打包前端
# os.chdir('/home/hberp/hb_client')
# os.system('npm run build:prod')
# os.system('\cp -rf /home/hberp/hb_client/dist/* /home/hberp/hb_server/vuedist')
return Response(ret.read())