正在显示
8 个修改的文件
包含
92 行增加
和
17 行删除
1 | +# Generated by Django 3.1.1 on 2020-10-21 11:40 | ||
2 | + | ||
3 | +from django.conf import settings | ||
4 | +from django.db import migrations, models | ||
5 | +import django.db.models.deletion | ||
6 | + | ||
7 | + | ||
8 | +class Migration(migrations.Migration): | ||
9 | + | ||
10 | + dependencies = [ | ||
11 | + migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
12 | + ('project', '0004_auto_20201014_1513'), | ||
13 | + ] | ||
14 | + | ||
15 | + operations = [ | ||
16 | + migrations.AddField( | ||
17 | + model_name='auditor', | ||
18 | + name='type', | ||
19 | + field=models.PositiveSmallIntegerField(choices=[(1, '市场容量小于300万美金'), (2, '市场容量大于等于300万美金')], default=1, verbose_name='项目类型'), | ||
20 | + ), | ||
21 | + migrations.AddField( | ||
22 | + model_name='project', | ||
23 | + name='first_orders', | ||
24 | + field=models.PositiveIntegerField(default=0, verbose_name='首单数量'), | ||
25 | + ), | ||
26 | + migrations.AddField( | ||
27 | + model_name='project', | ||
28 | + name='orders_estimate', | ||
29 | + field=models.CharField(default='', max_length=255, verbose_name='月销量预估'), | ||
30 | + ), | ||
31 | + migrations.AddField( | ||
32 | + model_name='project', | ||
33 | + name='roi_report', | ||
34 | + field=models.CharField(default='', max_length=255, verbose_name='ROI报告'), | ||
35 | + ), | ||
36 | + migrations.AddField( | ||
37 | + model_name='project', | ||
38 | + name='type', | ||
39 | + field=models.PositiveSmallIntegerField(choices=[(1, '市场容量小于300万美金'), (2, '市场容量大于等于300万美金')], default=1, verbose_name='项目类型'), | ||
40 | + ), | ||
41 | + migrations.AlterField( | ||
42 | + model_name='auditor', | ||
43 | + name='user', | ||
44 | + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='aud', to=settings.AUTH_USER_MODEL, verbose_name='审批人员'), | ||
45 | + ), | ||
46 | + ] |
1 | from django.db import models | 1 | from django.db import models |
2 | from usercenter.models import User | 2 | from usercenter.models import User |
3 | 3 | ||
4 | -# users = User.objects.filter(is_active=True).values('username', 'id').all() | ||
5 | -# AUDITOR_CHOICE = [(i['id'], i['username']) for i in users] | ||
6 | -AUDITOR_CHOICE = [(2, '邓望明'), (3, '杜波')] | 4 | +PROJECT_TYPE = ( |
5 | + (1, u"市场容量小于300万美金"), | ||
6 | + (2, u"市场容量大于等于300万美金"), | ||
7 | + ) | ||
7 | 8 | ||
8 | 9 | ||
9 | class Auditor(models.Model): | 10 | class Auditor(models.Model): |
@@ -12,7 +13,6 @@ class Auditor(models.Model): | @@ -12,7 +13,6 @@ class Auditor(models.Model): | ||
12 | User, | 13 | User, |
13 | on_delete=models.CASCADE, | 14 | on_delete=models.CASCADE, |
14 | related_name="aud", | 15 | related_name="aud", |
15 | - choices=AUDITOR_CHOICE, | ||
16 | verbose_name="审批人员") | 16 | verbose_name="审批人员") |
17 | leader = models.ForeignKey( | 17 | leader = models.ForeignKey( |
18 | 'self', | 18 | 'self', |
@@ -21,6 +21,7 @@ class Auditor(models.Model): | @@ -21,6 +21,7 @@ class Auditor(models.Model): | ||
21 | null=True, | 21 | null=True, |
22 | blank=True, | 22 | blank=True, |
23 | verbose_name="上级领导") | 23 | verbose_name="上级领导") |
24 | + type = models.PositiveSmallIntegerField(default=1, choices=PROJECT_TYPE, verbose_name="项目类型") | ||
24 | order = models.PositiveSmallIntegerField(default=0, null=True, blank=True, verbose_name="排序") | 25 | order = models.PositiveSmallIntegerField(default=0, null=True, blank=True, verbose_name="排序") |
25 | 26 | ||
26 | def __str__(self): | 27 | def __str__(self): |
@@ -31,13 +32,17 @@ class Auditor(models.Model): | @@ -31,13 +32,17 @@ class Auditor(models.Model): | ||
31 | 32 | ||
32 | 33 | ||
33 | class Project(models.Model): | 34 | class Project(models.Model): |
35 | + | ||
34 | category = models.CharField(max_length=100, default="", verbose_name="产品类目") | 36 | category = models.CharField(max_length=100, default="", verbose_name="产品类目") |
35 | model_type = models.CharField(max_length=50, default="", verbose_name="产品型号") | 37 | model_type = models.CharField(max_length=50, default="", verbose_name="产品型号") |
36 | market_share_analysis = models.TextField(default="", verbose_name="产品市场占有率分析") | 38 | market_share_analysis = models.TextField(default="", verbose_name="产品市场占有率分析") |
37 | context_analysis = models.TextField(default="", verbose_name="产品场景分析") | 39 | context_analysis = models.TextField(default="", verbose_name="产品场景分析") |
38 | attachments = models.CharField(max_length=800, default="", verbose_name="附件地址") | 40 | attachments = models.CharField(max_length=800, default="", verbose_name="附件地址") |
41 | + first_orders = models.PositiveIntegerField(default=0, verbose_name="首单数量") | ||
42 | + orders_estimate = models.CharField(default="", max_length=255, verbose_name="月销量预估") | ||
39 | auditor = models.ManyToManyField(Auditor, related_name="project_auditor", blank=True, verbose_name="审核人员") | 43 | auditor = models.ManyToManyField(Auditor, related_name="project_auditor", blank=True, verbose_name="审核人员") |
40 | is_done = models.BooleanField(default=False, blank=True, verbose_name="是否完成") | 44 | is_done = models.BooleanField(default=False, blank=True, verbose_name="是否完成") |
45 | + type = models.PositiveSmallIntegerField(default=1, choices=PROJECT_TYPE, verbose_name="项目类型") | ||
41 | is_pass = models.BooleanField(null=True, blank=True, verbose_name="是否通过") | 46 | is_pass = models.BooleanField(null=True, blank=True, verbose_name="是否通过") |
42 | create_time = models.DateTimeField(auto_now_add=True) | 47 | create_time = models.DateTimeField(auto_now_add=True) |
43 | creator = models.ForeignKey(User, related_name="project_creator", on_delete=models.CASCADE, verbose_name="创建人员") | 48 | creator = models.ForeignKey(User, related_name="project_creator", on_delete=models.CASCADE, verbose_name="创建人员") |
@@ -23,7 +23,7 @@ class ProjectSerializer(serializers.ModelSerializer): | @@ -23,7 +23,7 @@ class ProjectSerializer(serializers.ModelSerializer): | ||
23 | model = Project | 23 | model = Project |
24 | fields = ( | 24 | fields = ( |
25 | 'id', 'result', 'creator_name', 'category', 'model_type', 'market_share_analysis', 'context_analysis', | 25 | 'id', 'result', 'creator_name', 'category', 'model_type', 'market_share_analysis', 'context_analysis', |
26 | - 'attachments', 'create_time', "is_done", "is_pass" | 26 | + 'attachments', 'create_time', "is_done", "is_pass", "type", "orders_estimate", "first_orders" |
27 | ) | 27 | ) |
28 | depth = 1 | 28 | depth = 1 |
29 | 29 |
@@ -35,17 +35,18 @@ class CreateProject(CreateAPIView): | @@ -35,17 +35,18 @@ class CreateProject(CreateAPIView): | ||
35 | if not serializer.is_valid(): | 35 | if not serializer.is_valid(): |
36 | raise ValidationError(serializer.errors) | 36 | raise ValidationError(serializer.errors) |
37 | else: | 37 | else: |
38 | - serializer.save(creator=request.user, auditor=Auditor.objects.order_by('-order').all()) | ||
39 | - # 企业微信推送 | ||
40 | obj_dict = serializer.data | 38 | obj_dict = serializer.data |
41 | - for i in AUDITORS: | 39 | + auditors = Auditor.objects.filter(type=obj_dict['type']).order_by('order') |
40 | + serializer.save(creator=request.user, auditor=auditors) | ||
41 | + # 企业微信推送 | ||
42 | + for i in auditors: | ||
42 | Result.objects.create( | 43 | Result.objects.create( |
43 | - auditor_id=i[0], | 44 | + auditor_id=i.pk, |
44 | project_id=obj_dict['id'] | 45 | project_id=obj_dict['id'] |
45 | ) | 46 | ) |
46 | url = re.sub("PK", str(obj_dict['id']), FRONT_URL['flow_detail']) | 47 | url = re.sub("PK", str(obj_dict['id']), FRONT_URL['flow_detail']) |
47 | url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), FRONT_URL['wx_authorize']) | 48 | url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), FRONT_URL['wx_authorize']) |
48 | - first_auditor = Auditor.objects.filter(pk=AUDITORS[0][0]).first() | 49 | + first_auditor = auditors[0] |
49 | 50 | ||
50 | wx_client.push_card(first_auditor.user.wx_token, url, f"{request.user.username}提交了一个产品立项申请") | 51 | wx_client.push_card(first_auditor.user.wx_token, url, f"{request.user.username}提交了一个产品立项申请") |
51 | wx_client.push_card(request.user.wx_token, url, u"流程创建成功") | 52 | wx_client.push_card(request.user.wx_token, url, u"流程创建成功") |
@@ -61,8 +62,7 @@ class ProjectDetail(RetrieveAPIView): | @@ -61,8 +62,7 @@ class ProjectDetail(RetrieveAPIView): | ||
61 | obj = self.get_object() | 62 | obj = self.get_object() |
62 | obj.creator_name = obj.creator.username | 63 | obj.creator_name = obj.creator.username |
63 | obj.result = [] | 64 | obj.result = [] |
64 | - auditors = Auditor.objects.all() | ||
65 | - # result = Result.objects.filter(project=obj) | 65 | + auditors = Auditor.objects.filter(type=obj.type) |
66 | for i in auditors: | 66 | for i in auditors: |
67 | res = i.result_auditor.filter(project=obj).values('is_accept', 'memo').first() | 67 | res = i.result_auditor.filter(project=obj).values('is_accept', 'memo').first() |
68 | obj.result.append({ | 68 | obj.result.append({ |
@@ -94,12 +94,14 @@ class AuditProject(UpdateAPIView): | @@ -94,12 +94,14 @@ class AuditProject(UpdateAPIView): | ||
94 | ('reject', '否决') | 94 | ('reject', '否决') |
95 | ) | 95 | ) |
96 | accept_param = accept_choices[0][0] if request.data.get('is_accept') else accept_choices[1][0] | 96 | accept_param = accept_choices[0][0] if request.data.get('is_accept') else accept_choices[1][0] |
97 | - target = Project.objects.filter(auditor__user_id=request.user.id, pk=obj.id) | ||
98 | - if not target: | 97 | + # target = Project.objects.filter(auditor__user_id=request.user.id, pk=obj.id) |
98 | + if not obj: | ||
99 | raise PermissionError | 99 | raise PermissionError |
100 | else: | 100 | else: |
101 | auditor = Auditor.objects.get(user=request.user) | 101 | auditor = Auditor.objects.get(user=request.user) |
102 | - result = Result.objects.filter(auditor=auditor, project=obj).first() | 102 | + result = Result.objects.filter(auditor=auditor, project=obj, is_accept__isnull=True).order_by('pk').first() |
103 | + if not result: | ||
104 | + raise PermissionError("不允许修改已审核的项目") | ||
103 | result.is_accept = accept_param | 105 | result.is_accept = accept_param |
104 | result.memo = request.data.get('memo', '') | 106 | result.memo = request.data.get('memo', '') |
105 | result.save() | 107 | result.save() |
@@ -117,7 +119,9 @@ class AuditProject(UpdateAPIView): | @@ -117,7 +119,9 @@ class AuditProject(UpdateAPIView): | ||
117 | obj.is_done = True | 119 | obj.is_done = True |
118 | obj.is_pass = False | 120 | obj.is_pass = False |
119 | else: | 121 | else: |
120 | - second_auditor = Auditor.objects.filter(pk=AUDITORS[1][0]).first() | 122 | + next_auditor_id = Result.objects.filter(project=obj, is_accept__isnull=True)\ |
123 | + .values_list('auditor_id', flat=True).order_by('pk').first() | ||
124 | + second_auditor = Auditor.objects.filter(pk=next_auditor_id).first() | ||
121 | wx_client.push_card(second_auditor.user.wx_token, url, f"{request.user.username}已审核了一个产品立项申请") | 125 | wx_client.push_card(second_auditor.user.wx_token, url, f"{request.user.username}已审核了一个产品立项申请") |
122 | obj.save() | 126 | obj.save() |
123 | wx_client.push_card(obj.creator.wx_token, url, desc) | 127 | wx_client.push_card(obj.creator.wx_token, url, desc) |
1 | +# Generated by Django 3.1.1 on 2020-10-21 13:10 | ||
2 | + | ||
3 | +from django.db import migrations, models | ||
4 | + | ||
5 | + | ||
6 | +class Migration(migrations.Migration): | ||
7 | + | ||
8 | + dependencies = [ | ||
9 | + ('usercenter', '0001_initial'), | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.AddField( | ||
14 | + model_name='media', | ||
15 | + name='file_name', | ||
16 | + field=models.CharField(default='', max_length=100, verbose_name='文件名'), | ||
17 | + ), | ||
18 | + ] |
@@ -108,6 +108,7 @@ class Media(models.Model): | @@ -108,6 +108,7 @@ class Media(models.Model): | ||
108 | file = models.FileField(max_length=200, upload_to="%Y-%m-%d", verbose_name="文件地址") | 108 | file = models.FileField(max_length=200, upload_to="%Y-%m-%d", verbose_name="文件地址") |
109 | size = models.PositiveIntegerField(verbose_name="文件大小", null=True, blank=True) | 109 | size = models.PositiveIntegerField(verbose_name="文件大小", null=True, blank=True) |
110 | user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="uploader", verbose_name="上传用户") | 110 | user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="uploader", verbose_name="上传用户") |
111 | + file_name = models.CharField(max_length=100, default="", verbose_name="文件名") | ||
111 | extension = models.CharField(max_length=10, verbose_name="文件扩展名", choices=UPLOAD_MEDIA_CHOICES) | 112 | extension = models.CharField(max_length=10, verbose_name="文件扩展名", choices=UPLOAD_MEDIA_CHOICES) |
112 | create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") | 113 | create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间") |
113 | hash = models.CharField(max_length=200, verbose_name="文件哈希", null=True, blank=True) | 114 | hash = models.CharField(max_length=200, verbose_name="文件哈希", null=True, blank=True) |
@@ -54,7 +54,7 @@ class GroupSerializer(serializers.ModelSerializer): | @@ -54,7 +54,7 @@ class GroupSerializer(serializers.ModelSerializer): | ||
54 | class MediaSerializer(serializers.ModelSerializer): | 54 | class MediaSerializer(serializers.ModelSerializer): |
55 | class Meta: | 55 | class Meta: |
56 | model = Media | 56 | model = Media |
57 | - fields = ('file', 'size', 'create_time') | 57 | + fields = ('file', 'size', 'create_time', 'file_name') |
58 | 58 | ||
59 | 59 | ||
60 | 60 |
@@ -46,6 +46,7 @@ class UploadMedia(CreateAPIView): | @@ -46,6 +46,7 @@ class UploadMedia(CreateAPIView): | ||
46 | if not file: | 46 | if not file: |
47 | file = Media.objects.create( | 47 | file = Media.objects.create( |
48 | file=uploaded_file, | 48 | file=uploaded_file, |
49 | + file_name=uploaded_file.name, | ||
49 | hash=file_hash, | 50 | hash=file_hash, |
50 | user=request.user, | 51 | user=request.user, |
51 | size=file_size, | 52 | size=file_size, |
-
请 注册 或 登录 后发表评论