From 0487fac0c2393b0525a28a9c9b075e820f51c76f Mon Sep 17 00:00:00 2001 From: caoqianming Date: Fri, 21 Aug 2020 15:52:15 +0800 Subject: [PATCH] =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E5=88=B6=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/apps/certset/models.py | 4 +- server/apps/certset/serializers.py | 23 ++++++- server/apps/certset/views.py | 2 +- server/apps/project/filters.py | 8 +++ .../project/migrations/0020_unit_standard.py | 20 ++++++ .../migrations/0021_auto_20200818_1153.py | 33 ++++++++++ .../migrations/0022_auto_20200818_1704.py | 47 +++++++++++++ .../migrations/0023_auto_20200821_0957.py | 22 +++++++ .../migrations/0024_project_assign_by.py | 21 ++++++ .../migrations/0025_auto_20200821_1541.py | 46 +++++++++++++ server/apps/project/models.py | 53 ++++++++++++++- server/apps/project/serializers.py | 18 ++++- server/apps/project/urls.py | 1 + server/apps/project/views.py | 66 +++++++++++++++++-- server/apps/system/permission_data.py | 4 +- 15 files changed, 348 insertions(+), 20 deletions(-) create mode 100644 server/apps/project/filters.py create mode 100644 server/apps/project/migrations/0020_unit_standard.py create mode 100644 server/apps/project/migrations/0021_auto_20200818_1153.py create mode 100644 server/apps/project/migrations/0022_auto_20200818_1704.py create mode 100644 server/apps/project/migrations/0023_auto_20200821_0957.py create mode 100644 server/apps/project/migrations/0024_project_assign_by.py create mode 100644 server/apps/project/migrations/0025_auto_20200821_1541.py diff --git a/server/apps/certset/models.py b/server/apps/certset/models.py index 70b68ce..2b4b79e 100644 --- a/server/apps/certset/models.py +++ b/server/apps/certset/models.py @@ -22,7 +22,7 @@ class Standard(CommonAModel): verbose_name_plural = verbose_name def __str__(self): - return self.name + return self.code + '-' + self.name class ImplementRule(CommonAModel): @@ -44,7 +44,7 @@ class ImplementRule(CommonAModel): verbose_name_plural = verbose_name def __str__(self): - return self.name + return self.code +'-'+ self.name class UnitType(CommonAModel): diff --git a/server/apps/certset/serializers.py b/server/apps/certset/serializers.py index 7f8d725..4a1d049 100644 --- a/server/apps/certset/serializers.py +++ b/server/apps/certset/serializers.py @@ -6,31 +6,50 @@ from apps.system.serializers import DictSerializer class StandardSerializer(serializers.ModelSerializer): + fullname = serializers.SerializerMethodField(read_only=True) class Meta: model = Standard fields = '__all__' + def get_fullname(self, obj): + fullname = obj.code + ' ' + obj.name + if obj.code in obj.name: + fullname = obj.name + return fullname + class ImplementRuleSerializer(serializers.ModelSerializer): cert_field_ = DictSerializer(source='cert_field', read_only=True) + fullname = serializers.SerializerMethodField(read_only=True) class Meta: model = ImplementRule fields = '__all__' + + def get_fullname(self, obj): + fullname = obj.code + ' ' + obj.name + if obj.code in obj.name: + fullname = obj.name + return fullname class ImplementRuleListSerializer(serializers.ModelSerializer): pv_scope = DictSerializer() pv_class = DictSerializer() cert_field = DictSerializer() ccc_list = DictSerializer(many=True) + fullname = serializers.SerializerMethodField(read_only=True) class Meta: model = ImplementRule - fields = ['id', 'code', 'name', 'cert_field', 'pv_scope', 'pv_class', 'create_time', 'ccc_list'] + fields = ['id', 'code', 'name', 'cert_field', 'pv_scope', 'pv_class', 'create_time', 'ccc_list', 'fullname'] @staticmethod def setup_eager_loading(queryset): """ Perform necessary eager loading of data. """ queryset = queryset.select_related('pv_scope','pv_class', 'cert_field') queryset = queryset.prefetch_related('ccc_list',) return queryset - + def get_fullname(self, obj): + fullname = obj.code + ' ' + obj.name + if obj.code in obj.name: + fullname = obj.name + return fullname # def get_cert_field(self, obj): # return obj.get_cert_field_display() diff --git a/server/apps/certset/views.py b/server/apps/certset/views.py index 81f99f4..be94725 100644 --- a/server/apps/certset/views.py +++ b/server/apps/certset/views.py @@ -21,7 +21,7 @@ class ImplementRuleViewSet(CreateUpdateCustomMixin, OptimizationMixin, ModelView queryset = ImplementRule.objects.all() serializer_class = ImplementRuleSerializer search_fields = ['name', 'code', 'cert_field'] - filterset_fields = ['pv_scope', 'cert_field', 'cert_field__code'] + filterset_fields = ['pv_scope', 'cert_field', 'cert_field__code', 'ccc_list'] ordering = ['-create_time'] def get_serializer_class(self): diff --git a/server/apps/project/filters.py b/server/apps/project/filters.py new file mode 100644 index 0000000..450b007 --- /dev/null +++ b/server/apps/project/filters.py @@ -0,0 +1,8 @@ +from django_filters import rest_framework as filters +from .models import * + +class CertAppFilter(filters.FilterSet): + noproject = filters.BooleanFilter(field_name='project', lookup_expr='isnull') + class Meta: + model = CertApp + fields = ['status', 'noproject'] \ No newline at end of file diff --git a/server/apps/project/migrations/0020_unit_standard.py b/server/apps/project/migrations/0020_unit_standard.py new file mode 100644 index 0000000..3ae6454 --- /dev/null +++ b/server/apps/project/migrations/0020_unit_standard.py @@ -0,0 +1,20 @@ +# Generated by Django 3.0.7 on 2020-08-17 01:48 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('certset', '0016_auto_20200805_1435'), + ('project', '0019_auto_20200813_1744'), + ] + + operations = [ + migrations.AddField( + model_name='unit', + name='standard', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='certset.Standard', verbose_name='采用标准'), + ), + ] diff --git a/server/apps/project/migrations/0021_auto_20200818_1153.py b/server/apps/project/migrations/0021_auto_20200818_1153.py new file mode 100644 index 0000000..c6ab8a4 --- /dev/null +++ b/server/apps/project/migrations/0021_auto_20200818_1153.py @@ -0,0 +1,33 @@ +# Generated by Django 3.0.7 on 2020-08-18 03:53 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('certset', '0016_auto_20200805_1435'), + ('project', '0020_unit_standard'), + ] + + operations = [ + migrations.AddField( + model_name='unit', + name='implementrule', + field=models.ForeignKey(default=6, on_delete=django.db.models.deletion.DO_NOTHING, to='certset.ImplementRule', verbose_name='采用规则'), + preserve_default=False, + ), + migrations.AlterField( + model_name='unit', + name='standard', + field=models.ForeignKey(default=2, on_delete=django.db.models.deletion.DO_NOTHING, to='certset.Standard', verbose_name='采用标准'), + preserve_default=False, + ), + migrations.AlterField( + model_name='unit', + name='unittype', + field=models.ForeignKey(default=4, on_delete=django.db.models.deletion.DO_NOTHING, to='certset.UnitType', verbose_name='单元类型'), + preserve_default=False, + ), + ] diff --git a/server/apps/project/migrations/0022_auto_20200818_1704.py b/server/apps/project/migrations/0022_auto_20200818_1704.py new file mode 100644 index 0000000..6a1550e --- /dev/null +++ b/server/apps/project/migrations/0022_auto_20200818_1704.py @@ -0,0 +1,47 @@ +# Generated by Django 3.0.7 on 2020-08-18 09:04 + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('crm', '0011_enterprise_parent'), + ('project', '0021_auto_20200818_1153'), + ] + + operations = [ + migrations.AddField( + model_name='certapp', + name='scope', + field=models.TextField(blank=True, null=True, verbose_name='认证范围'), + ), + migrations.AddField( + model_name='project', + name='assign_date', + field=models.DateField(blank=True, null=True, verbose_name='下达日期'), + ), + migrations.AddField( + model_name='project', + name='auditee', + field=models.ForeignKey(default=43, on_delete=django.db.models.deletion.DO_NOTHING, related_name='project_auditee', to='crm.Enterprise', verbose_name='受审核方'), + preserve_default=False, + ), + migrations.AddField( + model_name='project', + name='auditee_v', + field=django.contrib.postgres.fields.jsonb.JSONField(default=dict, verbose_name='受审核方'), + ), + migrations.AddField( + model_name='project', + name='number', + field=models.CharField(blank=True, max_length=100, null=True, verbose_name='项目编号'), + ), + migrations.AddField( + model_name='project', + name='remark', + field=models.TextField(blank=True, null=True, verbose_name='备注'), + ), + ] diff --git a/server/apps/project/migrations/0023_auto_20200821_0957.py b/server/apps/project/migrations/0023_auto_20200821_0957.py new file mode 100644 index 0000000..123e1f5 --- /dev/null +++ b/server/apps/project/migrations/0023_auto_20200821_0957.py @@ -0,0 +1,22 @@ +# Generated by Django 3.0.7 on 2020-08-21 01:57 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('project', '0022_auto_20200818_1704'), + ] + + operations = [ + migrations.AlterModelOptions( + name='project', + options={'verbose_name': '认证项目', 'verbose_name_plural': '认证项目'}, + ), + migrations.AddField( + model_name='project', + name='status', + field=models.CharField(choices=[('待下达', '待下达'), ('待派差', '待派差'), ('进行中', '进行中'), ('已中止', '已中止'), ('已完成', '已完成')], default='待下达', max_length=50, verbose_name='项目状态'), + ), + ] diff --git a/server/apps/project/migrations/0024_project_assign_by.py b/server/apps/project/migrations/0024_project_assign_by.py new file mode 100644 index 0000000..e9a5745 --- /dev/null +++ b/server/apps/project/migrations/0024_project_assign_by.py @@ -0,0 +1,21 @@ +# Generated by Django 3.0.7 on 2020-08-21 02:04 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('project', '0023_auto_20200821_0957'), + ] + + operations = [ + migrations.AddField( + model_name='project', + name='assign_by', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='下达人'), + ), + ] diff --git a/server/apps/project/migrations/0025_auto_20200821_1541.py b/server/apps/project/migrations/0025_auto_20200821_1541.py new file mode 100644 index 0000000..678c380 --- /dev/null +++ b/server/apps/project/migrations/0025_auto_20200821_1541.py @@ -0,0 +1,46 @@ +# Generated by Django 3.0.7 on 2020-08-21 07:41 + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('system', '0028_auto_20200807_1018'), + ('project', '0024_project_assign_by'), + ] + + operations = [ + migrations.AddField( + model_name='project', + name='can_paichai', + field=models.BooleanField(default=False, verbose_name='是否可派差'), + ), + migrations.CreateModel( + name='Plan', + fields=[ + ('id', models.AutoField(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='删除标记')), + ('name', models.CharField(max_length=1000, verbose_name='计划名称')), + ('month', models.DateField(blank=True, null=True, verbose_name='计划审核月份')), + ('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plan_belong_dept', to='system.Organization', verbose_name='所属部门')), + ('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plan_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')), + ('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='plan_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')), + ], + options={ + 'verbose_name': '审核计划', + 'verbose_name_plural': '审核计划', + }, + ), + migrations.AddField( + model_name='project', + name='plan', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='project.Plan', verbose_name='所属计划'), + ), + ] diff --git a/server/apps/project/models.py b/server/apps/project/models.py index e4b99ad..d9bde9b 100644 --- a/server/apps/project/models.py +++ b/server/apps/project/models.py @@ -4,17 +4,54 @@ from django.db import models from rest_framework.exceptions import ParseError from simple_history.models import HistoricalRecords -from apps.certset.models import ImplementRule, UnitType, EvaluationItem +from apps.certset.models import ImplementRule, UnitType, EvaluationItem, Standard from apps.crm.models import Enterprise from apps.system.models import CommonAModel, CommonBModel, Dict, User # Create your models here. +class Plan(CommonBModel): + """ + 计划(项目组) + """ + name = models.CharField('计划名称', max_length = 1000) + month = models.DateField('计划审核月份', null=True, blank=True) + + class Meta: + verbose_name = '审核计划' + verbose_name_plural = verbose_name + + def __str__(self): + return self.name + class Project(CommonBModel): """ 认证项目 """ - pass + status_choices = ( + ('待下达', '待下达'), + ('待派差', '待派差'), + ('进行中', '进行中'), + ('已中止', '已中止'), + ('已完成', '已完成') + ) + status = models.CharField('项目状态', choices=status_choices, default='待下达', max_length=50) + number = models.CharField('项目编号', max_length = 100, null=True, blank=True) + auditee = models.ForeignKey(Enterprise, related_name='project_auditee', on_delete=models.DO_NOTHING, verbose_name='受审核方') + auditee_v = JSONField(verbose_name='受审核方', default=dict) + remark = models.TextField('备注', null=True, blank=True) + assign_date = models.DateField('下达日期', null=True, blank=True) + assign_by = models.ForeignKey(User, verbose_name='下达人', on_delete=models.SET_NULL, null=True, blank=True) + can_paichai = models.BooleanField('是否可派差', default = False) + plan = models.ForeignKey(Plan, verbose_name='所属计划', on_delete=models.SET_NULL, null=True, blank=True) + + + class Meta: + verbose_name = '认证项目' + verbose_name_plural = verbose_name + + def __str__(self): + return self.number class CertApp(CommonBModel): """ @@ -60,6 +97,7 @@ class CertApp(CommonBModel): manufacture_v = JSONField(verbose_name='制造商', null=True) factory = models.ForeignKey(Enterprise, on_delete=models.CASCADE, related_name='certapp_factory', null=True, blank=True) factory_v = JSONField(verbose_name='生产厂', null=True) + scope = models.TextField('认证范围', null=True, blank=True) class Meta: verbose_name = '认证受理' @@ -161,7 +199,9 @@ class Unit(CommonBModel): """ name = models.CharField('单元名称', max_length=200) description = models.TextField('单元描述', blank=True) - unittype = models.ForeignKey(UnitType, verbose_name='单元类型', on_delete = models.SET_NULL, null=True, blank=True) + implementrule = models.ForeignKey(ImplementRule, verbose_name='采用规则', on_delete=models.DO_NOTHING) + unittype = models.ForeignKey(UnitType, verbose_name='单元类型', on_delete = models.DO_NOTHING) + standard = models.ForeignKey(Standard, verbose_name='采用标准', on_delete = models.DO_NOTHING) certapp = models.ForeignKey(CertApp, verbose_name='所属业务', on_delete = models.CASCADE) class Meta: @@ -171,3 +211,10 @@ class Unit(CommonBModel): def __str__(self): return self.name + def save(self, *args, **kwargs): + super().save(*args, **kwargs) + obj = self.certapp + objs = Unit.objects.filter(certapp=obj, is_deleted=False).values_list('name', flat=True) + obj.scope = obj.factory_v['address'] + ':' + ';'.join(objs) + obj.save() + diff --git a/server/apps/project/serializers.py b/server/apps/project/serializers.py index 2898f8a..b7d40e7 100644 --- a/server/apps/project/serializers.py +++ b/server/apps/project/serializers.py @@ -3,7 +3,7 @@ from rest_framework import serializers from .models import * from apps.system.serializers import DictSerializer, UserListSerializer -# from apps.certset.serializers import ImplementRuleSerializer +from apps.certset.serializers import StandardSerializer class ApplicationCreateSerializer(serializers.ModelSerializer): number = serializers.CharField(required=False) @@ -46,6 +46,20 @@ class CertappSerializer(serializers.ModelSerializer): fields = '__all__' class UnitSerializer(serializers.ModelSerializer): + standard_ = StandardSerializer(source='standard', read_only=True) class Meta: model = Unit - fields = '__all__' \ No newline at end of file + fields = '__all__' + +class ProjectSerializer(serializers.ModelSerializer): + create_by_ = UserListSerializer(source='create_by', read_only=True) + certapps = serializers.SerializerMethodField() + class Meta: + model = Project + fields = '__all__' + + def get_certapps(self, obj): + certapps = [] + for i in CertApp.objects.filter(is_deleted=False, project=obj): + certapps.append(i.cert_field.code +'(' + i.cccpv_class.name +')') + return certapps \ No newline at end of file diff --git a/server/apps/project/urls.py b/server/apps/project/urls.py index 1a101e0..594ae1f 100644 --- a/server/apps/project/urls.py +++ b/server/apps/project/urls.py @@ -7,6 +7,7 @@ router.register('application', ApplicationViewSet, basename="application") router.register('subapplication', SubApplicationViewSet, basename="subapplication") router.register('certapp', CertappViewset, basename="certapp") router.register('unit', UnitViewSet, basename="unit") +router.register('project', ProjectViewSet, basename="project") urlpatterns = [ path('', include(router.urls)) ] \ No newline at end of file diff --git a/server/apps/project/views.py b/server/apps/project/views.py index 7416146..6c78d84 100644 --- a/server/apps/project/views.py +++ b/server/apps/project/views.py @@ -10,9 +10,10 @@ from apps.system.models import Dict from apps.system.permission_data import RbacFilterSet from apps.system.mixins import CreateUpdateCustomMixin, OptimizationMixin import random - +from rest_framework.decorators import action +from .filters import * # Create your views here. -class ApplicationViewSet(CreateUpdateCustomMixin, ModelViewSet): +class ApplicationViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet): """ 认证申请 """ @@ -30,7 +31,7 @@ class ApplicationViewSet(CreateUpdateCustomMixin, ModelViewSet): def perform_create(self, serializer): serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept, number=random.randrange(1000,2000)) -class SubApplicationViewSet(CreateUpdateCustomMixin, ModelViewSet): +class SubApplicationViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet): """ 子认证申请 """ @@ -61,7 +62,7 @@ class SubApplicationViewSet(CreateUpdateCustomMixin, ModelViewSet): return None return self.paginator.paginate_queryset(queryset, self.request, view=self) -class CertappViewset(CreateUpdateCustomMixin, ModelViewSet): +class CertappViewset(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet): """ 申请受理 """ @@ -69,24 +70,75 @@ class CertappViewset(CreateUpdateCustomMixin, ModelViewSet): queryset = CertApp.objects.all() serializer_class = CertappSerializer ordering = ['-create_time'] + filterset_fields = ['status', 'project'] + # filterset_class = CertAppFilter + def paginate_queryset(self, queryset): + + if ((not self.request.query_params.get('page', None)) and (self.request.query_params.get('status', None))) or (self.paginator is None): + return None + return self.paginator.paginate_queryset(queryset, self.request, view=self) + + return queryset def create(self, request, *args, **kwargs): postdata = request.data postdata['number'] = random.randrange(1000,2000) if postdata.get('field_code', None): postdata['cert_field'] = Dict.objects.get(code=postdata['field_code']).id - print(postdata) serializer = self.get_serializer(data=postdata) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) -class UnitViewSet(CreateUpdateCustomMixin, ModelViewSet): + @action(methods=['put'], detail=True, perms_map={'put':'complete_certapp'}, + url_name='complete_certapp') + def complete(self, request, pk=None): + """ + 完成受理 + """ + obj = self.get_object() + obj.status = '已受理' + obj.save() + return Response(status=status.HTTP_200_OK) + +class UnitViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet): """ 产品单元 """ perms_map = {'get': 'certapp_view', 'post':'certapp_create', 'put':'certapp_update','delete': 'certapp_delete'} queryset = Unit.objects.all() serializer_class = UnitSerializer - ordering = ['-create_time'] \ No newline at end of file + ordering = ['pk'] + filterset_fields = ['certapp'] + +class ProjectViewSet(CreateUpdateCustomMixin, RbacFilterSet, ModelViewSet): + perms_map = {'get': 'project_view', 'post':'project_create', 'put':'project_update','delete': 'project_delete'} + queryset = Project.objects.all() + serializer_class = ProjectSerializer + ordering = ['pk'] + + def create(self, request, *args, **kwargs): + postdata = request.data + postdata['number'] = random.randrange(8000,9000) + serializer = self.get_serializer(data=postdata) + serializer.is_valid(raise_exception=True) + instance = serializer.save(create_by = self.request.user, belong_dept=self.request.user.dept) + if 'certapps' in postdata and postdata['certapps']: + CertApp.objects.filter(pk__in = postdata['certapps']).update(project=instance, status='进行中') + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) + + @action(methods=['put'], detail=True, perms_map={'put':'project_assgin'}, + url_name='project_assgin') + def assgin(self, request, pk=None): + """ + 下达项目 + """ + obj = self.get_object() + if obj.status == '待下达': + obj.status = '待派差' + obj.save() + return Response(status=status.HTTP_200_OK) + else: + return Response('状态有误', status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file diff --git a/server/apps/system/permission_data.py b/server/apps/system/permission_data.py index 8b7d20f..e5550d9 100644 --- a/server/apps/system/permission_data.py +++ b/server/apps/system/permission_data.py @@ -50,9 +50,7 @@ class RbacFilterSet(CreateUpdateModelBMixin, object): return queryset elif '仅本人' in data_range: queryset = queryset.filter(Q(create_by=user)|Q(update_by=user)) - return queryset - if hasattr(self.get_serializer_class(), 'setup_eager_loading'): - queryset = self.get_serializer_class().setup_eager_loading(queryset) # 性能优化 + return queryset return queryset