diff --git a/hb_client/src/api/file.js b/hb_client/src/api/file.js
index 01c683e..9ad01c7 100644
--- a/hb_client/src/api/file.js
+++ b/hb_client/src/api/file.js
@@ -15,4 +15,11 @@ export function getFileList(query) {
method: 'get',
params: query
})
-}
\ No newline at end of file
+}
+export function upFile(data) {
+ return request({
+ url: '/file/',
+ method: 'post',
+ data
+ })
+}
diff --git a/hb_client/src/assets/glass.png b/hb_client/src/assets/glass.png
new file mode 100644
index 0000000..7b7c511
Binary files /dev/null and b/hb_client/src/assets/glass.png differ
diff --git a/hb_client/src/views/mtm/materialdo.vue b/hb_client/src/views/mtm/materialdo.vue
index 2795f0d..317fcf4 100644
--- a/hb_client/src/views/mtm/materialdo.vue
+++ b/hb_client/src/views/mtm/materialdo.vue
@@ -2,27 +2,34 @@
+
-
- 物料检验记录表
-
- 新增
+ 物料检验记录表
+
+
+ 新增
+
+
-
+
{{ scope.row.name }}
@@ -31,22 +38,26 @@
查看查看
+
编辑编辑
+
删除删除
+
+
-
+
取消
+ >取消
+
确认
+ >确认
+
+
-
+
-
-
+
+
+
@@ -124,11 +141,12 @@
:label="item.field_name"
>
@@ -137,9 +155,10 @@
:label="item.field_name"
>
@@ -169,26 +188,46 @@
+
+
+

+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
- 记录字段
+ 记录字段
新增新增
+
+
-
+
{{
scope.row.field_name
- }}
+ }}
+
{{
options_[scope.row.field_type]
- }}
+ }}
+
{{
scope.row.field_key
- }}
+ }}
+
-
+
-
+
-
+
+
+
-
+
+
-
-
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-!-->
-
-
-
-
-
-
-
取消取消
+
确认确认
+
@@ -439,329 +494,734 @@
diff --git a/hb_server/apps/mtm/migrations/0036_auto_20211123_1052.py b/hb_server/apps/mtm/migrations/0036_auto_20211123_1052.py
new file mode 100644
index 0000000..c0e36de
--- /dev/null
+++ b/hb_server/apps/mtm/migrations/0036_auto_20211123_1052.py
@@ -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='类型'),
+ ),
+ ]
diff --git a/hb_server/apps/mtm/models.py b/hb_server/apps/mtm/models.py
index 46e82b4..c6ebc6e 100644
--- a/hb_server/apps/mtm/models.py
+++ b/hb_server/apps/mtm/models.py
@@ -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 = '记录表格字段'
diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py
index 3e7a46d..f1b3ab8 100644
--- a/hb_server/apps/mtm/serializers.py
+++ b/hb_server/apps/mtm/serializers.py
@@ -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
diff --git a/hb_server/apps/pm/filters.py b/hb_server/apps/pm/filters.py
new file mode 100644
index 0000000..313c63d
--- /dev/null
+++ b/hb_server/apps/pm/filters.py
@@ -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
\ No newline at end of file
diff --git a/hb_server/apps/pm/migrations/0014_subproductionplan_number.py b/hb_server/apps/pm/migrations/0014_subproductionplan_number.py
new file mode 100644
index 0000000..e84a4d8
--- /dev/null
+++ b/hb_server/apps/pm/migrations/0014_subproductionplan_number.py
@@ -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='子计划编号'),
+ ),
+ ]
diff --git a/hb_server/apps/pm/migrations/0015_auto_20211122_1556.py b/hb_server/apps/pm/migrations/0015_auto_20211122_1556.py
new file mode 100644
index 0000000..1f00fa9
--- /dev/null
+++ b/hb_server/apps/pm/migrations/0015_auto_20211122_1556.py
@@ -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='合格数量'),
+ ),
+ ]
diff --git a/hb_server/apps/pm/models.py b/hb_server/apps/pm/models.py
index 663d885..9cdd6c1 100644
--- a/hb_server/apps/pm/models.py
+++ b/hb_server/apps/pm/models.py
@@ -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)
diff --git a/hb_server/apps/pm/serializers.py b/hb_server/apps/pm/serializers.py
index 90ff400..65980c0 100644
--- a/hb_server/apps/pm/serializers.py
+++ b/hb_server/apps/pm/serializers.py
@@ -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']
diff --git a/hb_server/apps/pm/urls.py b/hb_server/apps/pm/urls.py
index f6f6279..1d3f1eb 100644
--- a/hb_server/apps/pm/urls.py
+++ b/hb_server/apps/pm/urls.py
@@ -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)),
diff --git a/hb_server/apps/pm/views.py b/hb_server/apps/pm/views.py
index a86d146..aa02784 100644
--- a/hb_server/apps/pm/views.py
+++ b/hb_server/apps/pm/views.py
@@ -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):
diff --git a/hb_server/apps/qm/migrations/0011_auto_20211119_0848.py b/hb_server/apps/qm/migrations/0011_auto_20211119_0848.py
new file mode 100644
index 0000000..a643fe0
--- /dev/null
+++ b/hb_server/apps/qm/migrations/0011_auto_20211119_0848.py
@@ -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='自动判定的是否合格'),
+ ),
+ ]
diff --git a/hb_server/apps/qm/models.py b/hb_server/apps/qm/models.py
index fb61f53..c2dea88 100644
--- a/hb_server/apps/qm/models.py
+++ b/hb_server/apps/qm/models.py
@@ -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')
\ No newline at end of file
diff --git a/hb_server/apps/wpm/filters.py b/hb_server/apps/wpm/filters.py
new file mode 100644
index 0000000..eac725e
--- /dev/null
+++ b/hb_server/apps/wpm/filters.py
@@ -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
\ No newline at end of file
diff --git a/hb_server/apps/wpm/migrations/0016_auto_20211119_0848.py b/hb_server/apps/wpm/migrations/0016_auto_20211119_0848.py
new file mode 100644
index 0000000..e632e92
--- /dev/null
+++ b/hb_server/apps/wpm/migrations/0016_auto_20211119_0848.py
@@ -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='关联操作'),
+ ),
+ ]
diff --git a/hb_server/apps/wpm/migrations/0017_auto_20211119_1034.py b/hb_server/apps/wpm/migrations/0017_auto_20211119_1034.py
new file mode 100644
index 0000000..bbbaeaa
--- /dev/null
+++ b/hb_server/apps/wpm/migrations/0017_auto_20211119_1034.py
@@ -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,
+ },
+ ),
+ ]
diff --git a/hb_server/apps/wpm/migrations/0018_auto_20211119_1340.py b/hb_server/apps/wpm/migrations/0018_auto_20211119_1340.py
new file mode 100644
index 0000000..07b428c
--- /dev/null
+++ b/hb_server/apps/wpm/migrations/0018_auto_20211119_1340.py
@@ -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='关联操作'),
+ ),
+ ]
diff --git a/hb_server/apps/wpm/migrations/0019_auto_20211122_1110.py b/hb_server/apps/wpm/migrations/0019_auto_20211122_1110.py
new file mode 100644
index 0000000..aaffb4a
--- /dev/null
+++ b/hb_server/apps/wpm/migrations/0019_auto_20211122_1110.py
@@ -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='当前子生产计划'),
+ ),
+ ]
diff --git a/hb_server/apps/wpm/migrations/0020_alter_operationwproduct_wproduct.py b/hb_server/apps/wpm/migrations/0020_alter_operationwproduct_wproduct.py
new file mode 100644
index 0000000..45929df
--- /dev/null
+++ b/hb_server/apps/wpm/migrations/0020_alter_operationwproduct_wproduct.py
@@ -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='关联半成品'),
+ ),
+ ]
diff --git a/hb_server/apps/wpm/migrations/0021_auto_20211123_0945.py b/hb_server/apps/wpm/migrations/0021_auto_20211123_0945.py
new file mode 100644
index 0000000..c8b651a
--- /dev/null
+++ b/hb_server/apps/wpm/migrations/0021_auto_20211123_0945.py
@@ -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',
+ ),
+ ]
diff --git a/hb_server/apps/wpm/migrations/0022_auto_20211123_1425.py b/hb_server/apps/wpm/migrations/0022_auto_20211123_1425.py
new file mode 100644
index 0000000..bf6b8de
--- /dev/null
+++ b/hb_server/apps/wpm/migrations/0022_auto_20211123_1425.py
@@ -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'),
+ ),
+ ]
diff --git a/hb_server/apps/wpm/models.py b/hb_server/apps/wpm/models.py
index 8ec6790..db98eab 100644
--- a/hb_server/apps/wpm/models.py
+++ b/hb_server/apps/wpm/models.py
@@ -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)
\ No newline at end of file
diff --git a/hb_server/apps/wpm/serializers.py b/hb_server/apps/wpm/serializers.py
index fc6be42..ed2850a 100644
--- a/hb_server/apps/wpm/serializers.py
+++ b/hb_server/apps/wpm/serializers.py
@@ -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)
\ No newline at end of file
diff --git a/hb_server/apps/wpm/services.py b/hb_server/apps/wpm/services.py
index de6e5c8..20f2870 100644
--- a/hb_server/apps/wpm/services.py
+++ b/hb_server/apps/wpm/services.py
@@ -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
\ No newline at end of file
+ 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
\ No newline at end of file
diff --git a/hb_server/apps/wpm/urls.py b/hb_server/apps/wpm/urls.py
index 7c43ac7..57db6b9 100644
--- a/hb_server/apps/wpm/urls.py
+++ b/hb_server/apps/wpm/urls.py
@@ -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()),
diff --git a/hb_server/apps/wpm/views.py b/hb_server/apps/wpm/views.py
index 1b63890..cdb81de 100644
--- a/hb_server/apps/wpm/views.py
+++ b/hb_server/apps/wpm/views.py
@@ -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
diff --git a/hb_server/requirements.txt b/hb_server/requirements.txt
index a223cbc..3d3b1be 100644
--- a/hb_server/requirements.txt
+++ b/hb_server/requirements.txt
@@ -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
diff --git a/hb_server/server/urls.py b/hb_server/server/urls.py
index b5ac030..3db8e36 100644
--- a/hb_server/server/urls.py
+++ b/hb_server/server/urls.py
@@ -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"))
diff --git a/hb_server/utils/tools.py b/hb_server/utils/tools.py
index 786b8f2..73a6db6 100644
--- a/hb_server/utils/tools.py
+++ b/hb_server/utils/tools.py
@@ -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)
\ No newline at end of file
diff --git a/hb_server/utils/view.py b/hb_server/utils/view.py
index 23707ff..8b07565 100644
--- a/hb_server/utils/view.py
+++ b/hb_server/utils/view.py
@@ -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())