正在显示
27 个修改的文件
包含
706 行增加
和
36 行删除
@@ -13,7 +13,6 @@ from .models import Auditor, Project, Result | @@ -13,7 +13,6 @@ from .models import Auditor, Project, Result | ||
13 | from utils.helpers import WxPushHelper | 13 | from utils.helpers import WxPushHelper |
14 | from utils.pagination import MyPageNumberPagination | 14 | from utils.pagination import MyPageNumberPagination |
15 | from utils.util import response | 15 | from utils.util import response |
16 | -from wxProject.settings import FRONT_URL | ||
17 | from wxProject.qywx_settings import Conf, project_conf | 16 | from wxProject.qywx_settings import Conf, project_conf |
18 | 17 | ||
19 | 18 | ||
@@ -37,8 +36,8 @@ class CreateProject(CreateAPIView): | @@ -37,8 +36,8 @@ class CreateProject(CreateAPIView): | ||
37 | auditor_id=i.pk, | 36 | auditor_id=i.pk, |
38 | project_id=serializer.data['id'] | 37 | project_id=serializer.data['id'] |
39 | ) | 38 | ) |
40 | - url = re.sub("PK", str(obj_dict['id']), FRONT_URL['flow_detail']) | ||
41 | - url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), FRONT_URL['wx_authorize']) | 39 | + url = re.sub("PK", str(obj_dict['id']), project_conf['flow_detail']) |
40 | + url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), project_conf['wx_authorize']) | ||
42 | first_auditor = auditors[0] | 41 | first_auditor = auditors[0] |
43 | 42 | ||
44 | wx_client.push_card(first_auditor.user.wx_token, url, f"{request.user.username}提交了一个产品立项申请") | 43 | wx_client.push_card(first_auditor.user.wx_token, url, f"{request.user.username}提交了一个产品立项申请") |
@@ -101,8 +100,8 @@ class AuditProject(UpdateAPIView): | @@ -101,8 +100,8 @@ class AuditProject(UpdateAPIView): | ||
101 | 100 | ||
102 | wx_client = WxPushHelper(Conf[project_conf['APP_ID']]) | 101 | wx_client = WxPushHelper(Conf[project_conf['APP_ID']]) |
103 | full_audit_done = self._check_audit(obj) | 102 | full_audit_done = self._check_audit(obj) |
104 | - url = re.sub("PK", str(obj.id), FRONT_URL['flow_detail']) | ||
105 | - url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), FRONT_URL['wx_authorize']) | 103 | + url = re.sub("PK", str(obj.id), project_conf['flow_detail']) |
104 | + url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), project_conf['wx_authorize']) | ||
106 | desc = "产品立项流程所有审批已完成" if full_audit_done else f"{request.user.username}已审批完成" | 105 | desc = "产品立项流程所有审批已完成" if full_audit_done else f"{request.user.username}已审批完成" |
107 | if full_audit_done: | 106 | if full_audit_done: |
108 | obj.is_done = True | 107 | obj.is_done = True |
不能预览此文件类型
sku/__pycache__/serializers.cpython-38.pyc
0 → 100644
不能预览此文件类型
sku/__pycache__/urls.cpython-38.pyc
0 → 100644
不能预览此文件类型
sku/__pycache__/views.cpython-38.pyc
0 → 100644
不能预览此文件类型
sku/migrations/0001_initial.py
0 → 100644
1 | +# Generated by Django 3.1.1 on 2020-11-03 08:15 | ||
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 | + initial = True | ||
11 | + | ||
12 | + dependencies = [ | ||
13 | + migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
14 | + ] | ||
15 | + | ||
16 | + operations = [ | ||
17 | + migrations.CreateModel( | ||
18 | + name='Auditor', | ||
19 | + fields=[ | ||
20 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
21 | + ('order', models.PositiveSmallIntegerField(blank=True, default=0, null=True, verbose_name='排序')), | ||
22 | + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sku_aud', to=settings.AUTH_USER_MODEL, verbose_name='审批人员')), | ||
23 | + ], | ||
24 | + options={ | ||
25 | + 'ordering': ('order',), | ||
26 | + }, | ||
27 | + ), | ||
28 | + migrations.CreateModel( | ||
29 | + name='Flow', | ||
30 | + fields=[ | ||
31 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
32 | + ('is_done', models.BooleanField(default=False, verbose_name='是否已结束')), | ||
33 | + ('create_time', models.DateTimeField(auto_now_add=True)), | ||
34 | + ('auditor', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to='sku.auditor', verbose_name='审核人员')), | ||
35 | + ('starter', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL, verbose_name='发起人')), | ||
36 | + ], | ||
37 | + ), | ||
38 | + migrations.CreateModel( | ||
39 | + name='SKU', | ||
40 | + fields=[ | ||
41 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
42 | + ('supplier', models.CharField(default='', max_length=100, verbose_name='供应商')), | ||
43 | + ('sku', models.CharField(default='', max_length=100, verbose_name='SKU')), | ||
44 | + ('model', models.CharField(default='', max_length=100, verbose_name='型号')), | ||
45 | + ('title', models.CharField(default='', max_length=100, verbose_name='SKU名称')), | ||
46 | + ('is_new', models.CharField(default='', max_length=100, verbose_name='是否新品')), | ||
47 | + ('qty', models.CharField(default='', max_length=100, verbose_name='需求单数量')), | ||
48 | + ('price_with_tax', models.DecimalField(decimal_places=4, default=0, max_digits=9, verbose_name='含税单价')), | ||
49 | + ('amount_with_tax', models.DecimalField(decimal_places=4, default=0, max_digits=9, verbose_name='含税总金额')), | ||
50 | + ('sell_day', models.PositiveIntegerField(default=0, null=True, verbose_name='可售天数')), | ||
51 | + ('qty_within_30', models.PositiveIntegerField(default=0, null=True, verbose_name='30天销量')), | ||
52 | + ('inventory', models.PositiveIntegerField(default=0, null=True, verbose_name='库存')), | ||
53 | + ('coming_inventory', models.PositiveIntegerField(default=0, null=True, verbose_name='采购在途')), | ||
54 | + ('gross_profit_rate', models.FloatField(default=0, null=True, verbose_name='毛利率')), | ||
55 | + ('return_rate', models.FloatField(default=0, null=True, verbose_name='客退率')), | ||
56 | + ('memo', models.CharField(default='', max_length=255, null=True, verbose_name='备注')), | ||
57 | + ('create_time', models.DateTimeField(auto_now_add=True)), | ||
58 | + ('purchaser', models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='purchase_user', to=settings.AUTH_USER_MODEL, verbose_name='采购')), | ||
59 | + ], | ||
60 | + ), | ||
61 | + migrations.CreateModel( | ||
62 | + name='Result', | ||
63 | + fields=[ | ||
64 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
65 | + ('is_accept', models.CharField(choices=[('accept', '通过'), ('reject', '否决')], max_length=10, null=True, verbose_name='审核项目')), | ||
66 | + ('memo', models.CharField(blank=True, default='', max_length=300, verbose_name='审核结果陈述')), | ||
67 | + ('create_time', models.DateTimeField(auto_now_add=True)), | ||
68 | + ('auditor', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='result_auditor', to='sku.auditor', verbose_name='审核人员')), | ||
69 | + ('flow', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='result_flow', to='sku.flow', verbose_name='审核项目')), | ||
70 | + ], | ||
71 | + options={ | ||
72 | + 'ordering': ('pk',), | ||
73 | + }, | ||
74 | + ), | ||
75 | + migrations.CreateModel( | ||
76 | + name='Leader', | ||
77 | + fields=[ | ||
78 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
79 | + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sku_leader', to=settings.AUTH_USER_MODEL, verbose_name='采购负责人')), | ||
80 | + ], | ||
81 | + ), | ||
82 | + migrations.CreateModel( | ||
83 | + name='FlowSKU', | ||
84 | + fields=[ | ||
85 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
86 | + ('is_pass', models.BooleanField(default=False, verbose_name='是否通过,默认为否')), | ||
87 | + ('flow', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sku.flow', verbose_name='对应的流程')), | ||
88 | + ('sku', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sku.sku', verbose_name='流程中的的SKU')), | ||
89 | + ], | ||
90 | + ), | ||
91 | + ] |
sku/migrations/0002_auto_20201103_1751.py
0 → 100644
1 | +# Generated by Django 3.1.1 on 2020-11-03 09:51 | ||
2 | + | ||
3 | +from django.db import migrations, models | ||
4 | + | ||
5 | + | ||
6 | +class Migration(migrations.Migration): | ||
7 | + | ||
8 | + dependencies = [ | ||
9 | + ('sku', '0001_initial'), | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.AlterField( | ||
14 | + model_name='sku', | ||
15 | + name='is_new', | ||
16 | + field=models.CharField(choices=[('是', '新品'), ('否', '非新品')], max_length=10, verbose_name='是否新品'), | ||
17 | + ), | ||
18 | + migrations.AlterField( | ||
19 | + model_name='sku', | ||
20 | + name='purchaser', | ||
21 | + field=models.CharField(max_length=255, verbose_name='采购名字'), | ||
22 | + ), | ||
23 | + migrations.AlterField( | ||
24 | + model_name='sku', | ||
25 | + name='supplier', | ||
26 | + field=models.CharField(default='', max_length=255, verbose_name='供应商'), | ||
27 | + ), | ||
28 | + ] |
sku/migrations/0003_auto_20201103_1818.py
0 → 100644
1 | +# Generated by Django 3.1.1 on 2020-11-03 10:18 | ||
2 | + | ||
3 | +from django.db import migrations, models | ||
4 | + | ||
5 | + | ||
6 | +class Migration(migrations.Migration): | ||
7 | + | ||
8 | + dependencies = [ | ||
9 | + ('sku', '0002_auto_20201103_1751'), | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.AlterField( | ||
14 | + model_name='sku', | ||
15 | + name='amount_with_tax', | ||
16 | + field=models.DecimalField(decimal_places=4, default=0, max_digits=12, verbose_name='含税总金额'), | ||
17 | + ), | ||
18 | + migrations.AlterField( | ||
19 | + model_name='sku', | ||
20 | + name='price_with_tax', | ||
21 | + field=models.DecimalField(decimal_places=4, default=0, max_digits=12, verbose_name='含税单价'), | ||
22 | + ), | ||
23 | + ] |
sku/migrations/0004_remove_flow_auditor.py
0 → 100644
1 | +# Generated by Django 3.1.1 on 2020-11-03 10:57 | ||
2 | + | ||
3 | +from django.db import migrations | ||
4 | + | ||
5 | + | ||
6 | +class Migration(migrations.Migration): | ||
7 | + | ||
8 | + dependencies = [ | ||
9 | + ('sku', '0003_auto_20201103_1818'), | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.RemoveField( | ||
14 | + model_name='flow', | ||
15 | + name='auditor', | ||
16 | + ), | ||
17 | + ] |
sku/migrations/0005_auto_20201105_1710.py
0 → 100644
1 | +# Generated by Django 3.1.1 on 2020-11-05 09:10 | ||
2 | + | ||
3 | +from django.db import migrations, models | ||
4 | +import django.db.models.deletion | ||
5 | + | ||
6 | + | ||
7 | +class Migration(migrations.Migration): | ||
8 | + | ||
9 | + dependencies = [ | ||
10 | + ('sku', '0004_remove_flow_auditor'), | ||
11 | + ] | ||
12 | + | ||
13 | + operations = [ | ||
14 | + migrations.AlterField( | ||
15 | + model_name='flowsku', | ||
16 | + name='flow', | ||
17 | + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sku_flow', to='sku.flow', verbose_name='对应的流程'), | ||
18 | + ), | ||
19 | + migrations.AlterField( | ||
20 | + model_name='flowsku', | ||
21 | + name='sku', | ||
22 | + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='flow_sku', to='sku.sku', verbose_name='流程中的的SKU'), | ||
23 | + ), | ||
24 | + migrations.AlterField( | ||
25 | + model_name='sku', | ||
26 | + name='memo', | ||
27 | + field=models.CharField(blank=True, default='', max_length=255, null=True, verbose_name='备注'), | ||
28 | + ), | ||
29 | + ] |
sku/migrations/0006_auto_20201105_1739.py
0 → 100644
1 | +# Generated by Django 3.1.1 on 2020-11-05 09:39 | ||
2 | + | ||
3 | +from django.db import migrations, models | ||
4 | + | ||
5 | + | ||
6 | +class Migration(migrations.Migration): | ||
7 | + | ||
8 | + dependencies = [ | ||
9 | + ('sku', '0005_auto_20201105_1710'), | ||
10 | + ] | ||
11 | + | ||
12 | + operations = [ | ||
13 | + migrations.AlterField( | ||
14 | + model_name='flowsku', | ||
15 | + name='is_pass', | ||
16 | + field=models.BooleanField(null=True, verbose_name='是否通过,默认为否'), | ||
17 | + ), | ||
18 | + ] |
不能预览此文件类型
不能预览此文件类型
不能预览此文件类型
不能预览此文件类型
不能预览此文件类型
不能预览此文件类型
1 | from django.db import models | 1 | from django.db import models |
2 | 2 | ||
3 | -# Create your models here. | 3 | + |
4 | +from usercenter.models import User | ||
5 | + | ||
6 | + | ||
7 | +class Auditor(models.Model): | ||
8 | + user = models.ForeignKey( | ||
9 | + User, | ||
10 | + on_delete=models.CASCADE, | ||
11 | + related_name="sku_aud", | ||
12 | + verbose_name="审批人员") | ||
13 | + order = models.PositiveSmallIntegerField(default=0, null=True, blank=True, verbose_name="排序") | ||
14 | + | ||
15 | + def __str__(self): | ||
16 | + return self.user.username | ||
17 | + | ||
18 | + class Meta: | ||
19 | + ordering = ('order', ) | ||
20 | + | ||
21 | + | ||
22 | +class SKU(models.Model): | ||
23 | + NEW_CHOICES = ( | ||
24 | + ("是", "新品"), | ||
25 | + ("否", "非新品") | ||
26 | + ) | ||
27 | + supplier = models.CharField(max_length=255, default="", verbose_name="供应商") | ||
28 | + sku = models.CharField(max_length=100, default="", verbose_name="SKU") | ||
29 | + model = models.CharField(max_length=100, default="", verbose_name="型号") | ||
30 | + title = models.CharField(max_length=100, default="", verbose_name="SKU名称") | ||
31 | + is_new = models.CharField(max_length=10, choices=NEW_CHOICES, verbose_name="是否新品") | ||
32 | + qty = models.CharField(max_length=100, default="", verbose_name="需求单数量") | ||
33 | + price_with_tax = models.DecimalField(max_digits=12, decimal_places=4, default=0, verbose_name="含税单价") | ||
34 | + amount_with_tax = models.DecimalField(max_digits=12, decimal_places=4, default=0, verbose_name="含税总金额") | ||
35 | + sell_day = models.PositiveIntegerField(default=0, null=True, verbose_name="可售天数") | ||
36 | + qty_within_30 = models.PositiveIntegerField(default=0, null=True, verbose_name="30天销量") | ||
37 | + inventory = models.PositiveIntegerField(default=0, null=True, verbose_name="库存") | ||
38 | + coming_inventory = models.PositiveIntegerField(default=0, null=True, verbose_name="采购在途") | ||
39 | + gross_profit_rate = models.FloatField(default=0, null=True, verbose_name="毛利率") | ||
40 | + return_rate = models.FloatField(default=0, null=True, verbose_name="客退率") | ||
41 | + memo = models.CharField(default="", max_length=255, null=True, verbose_name="备注", blank=True) | ||
42 | + create_time = models.DateTimeField(auto_now_add=True) | ||
43 | + purchaser = models.CharField(max_length=255, verbose_name="采购名字") | ||
44 | + | ||
45 | + | ||
46 | +class Flow(models.Model): | ||
47 | + """ 提交发起的流程""" | ||
48 | + starter = models.ForeignKey(User, on_delete=models.DO_NOTHING, verbose_name="发起人") | ||
49 | + is_done = models.BooleanField(default=False, verbose_name="是否已结束") | ||
50 | + create_time = models.DateTimeField(auto_now_add=True) | ||
51 | + | ||
52 | + | ||
53 | +class FlowSKU(models.Model): | ||
54 | + """ 流程中的SKU """ | ||
55 | + sku = models.ForeignKey(SKU, on_delete=models.CASCADE, verbose_name="流程中的的SKU", related_name="flow_sku") | ||
56 | + flow = models.ForeignKey(Flow, on_delete=models.CASCADE, verbose_name="对应的流程", related_name="sku_flow") | ||
57 | + is_pass = models.BooleanField(null=True, verbose_name="是否通过,默认为否") | ||
58 | + | ||
59 | + | ||
60 | +class Result(models.Model): | ||
61 | + ACCEPT_CHOICES = ( | ||
62 | + ('accept', '通过'), | ||
63 | + ('reject', '否决') | ||
64 | + ) | ||
65 | + | ||
66 | + auditor = models.ForeignKey(Auditor, on_delete=models.CASCADE, related_name="result_auditor", verbose_name="审核人员") | ||
67 | + flow = models.ForeignKey(Flow, on_delete=models.CASCADE, related_name="result_flow", verbose_name="审核项目") | ||
68 | + is_accept = models.CharField(max_length=10, null=True, choices=ACCEPT_CHOICES, verbose_name="审核项目") | ||
69 | + memo = models.CharField(max_length=300, blank=True, default="", verbose_name="审核结果陈述") | ||
70 | + create_time = models.DateTimeField(auto_now_add=True) | ||
71 | + | ||
72 | + class Meta: | ||
73 | + ordering = ('pk', ) | ||
74 | + | ||
75 | + | ||
76 | +class Leader(models.Model): | ||
77 | + """ 采购负责人""" | ||
78 | + user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="sku_leader", verbose_name="采购负责人") | ||
79 | + | ||
80 | + |
sku/serializers.py
0 → 100644
1 | +# _*_ coding: utf-8 _*_ | ||
2 | +# @Time : 2020/11/3 16:34 | ||
3 | +# @Author vanwhebin | ||
4 | + | ||
5 | +from rest_framework import serializers | ||
6 | + | ||
7 | +from .models import Auditor, Flow, Result, SKU, FlowSKU | ||
8 | + | ||
9 | + | ||
10 | +class AuditorSerializer(serializers.ModelSerializer): | ||
11 | + | ||
12 | + class Meta: | ||
13 | + model = Auditor | ||
14 | + fields = '__all__' | ||
15 | + depth = 1 | ||
16 | + | ||
17 | + | ||
18 | +class SKUSerializer(serializers.ModelSerializer): | ||
19 | + # pk = serializers.ReadOnlyField() | ||
20 | + # is_new = serializers.ReadOnlyField() | ||
21 | + # purchaser = serializers.ReadOnlyField() | ||
22 | + | ||
23 | + class Meta: | ||
24 | + model = SKU | ||
25 | + # fields = ("supplier", "sku", "model", "title", "is_new", "qty", "price_with_tax", "amount_with_tax", "sell_day", | ||
26 | + # "qty_within_30", "inventory", "coming_inventory", "gross_profit_rate", "return_rate", "memo", | ||
27 | + # "purchaser") | ||
28 | + fields = "__all__" | ||
29 | + | ||
30 | + | ||
31 | +class FlowSerializer(serializers.ModelSerializer): | ||
32 | + result = serializers.ReadOnlyField() | ||
33 | + creator_name = serializers.ReadOnlyField() | ||
34 | + skus = serializers.ReadOnlyField() | ||
35 | + | ||
36 | + class Meta: | ||
37 | + model = Flow | ||
38 | + fields = ("result", "creator_name", "skus", "is_done", "create_time") | ||
39 | + | ||
40 | + | ||
41 | +class FlowListSerializer(serializers.ModelSerializer): | ||
42 | + result = serializers.BooleanField() | ||
43 | + creator_name = serializers.CharField() | ||
44 | + flow_id = serializers.IntegerField() | ||
45 | + | ||
46 | + class Meta: | ||
47 | + model = Result | ||
48 | + fields = ("creator_name", "result", "flow_id", "create_time") | ||
49 | + | ||
50 | + | ||
51 | +class ResultSerializer(serializers.ModelSerializer): | ||
52 | + | ||
53 | + class Meta: | ||
54 | + model = Result | ||
55 | + fields = "__all__" | ||
56 | + | ||
57 | + | ||
58 | +class FlowSKUSerializer(serializers.ModelSerializer): | ||
59 | + | ||
60 | + class Meta: | ||
61 | + model = FlowSKU | ||
62 | + fields = "__all__" | ||
63 | + depth = 1 | ||
64 | + |
@@ -2,10 +2,17 @@ | @@ -2,10 +2,17 @@ | ||
2 | # @Time : 2020/11/2 18:41 | 2 | # @Time : 2020/11/2 18:41 |
3 | # @Author vanwhebin | 3 | # @Author vanwhebin |
4 | 4 | ||
5 | -from django.urls import path, include | 5 | +from django.urls import path |
6 | +from sku import views | ||
6 | 7 | ||
7 | app_name = "sku" | 8 | app_name = "sku" |
8 | 9 | ||
9 | urlpatterns = [ | 10 | urlpatterns = [ |
10 | - | 11 | + path('create', views.CreateSKUFlow.as_view(), name="create_sku_flow"), |
12 | + path('audit/<int:pk>', views.AuditFlow.as_view(), name="audit_flow"), | ||
13 | + path('right/<int:pk>', views.CheckAuth.as_view(), name="check_audit_auth"), | ||
14 | + path('list', views.AuditFlowList.as_view(), name="list_flow"), | ||
15 | + path('<int:pk>', views.FlowDetail.as_view(), name="retrieve_flow"), | ||
16 | + path('info/<int:pk>', views.UpdateSKUInfo.as_view(), name="update_sku"), | ||
17 | + path('template', views.ParseSKUExcel.as_view(), name="upload_sku_template"), | ||
11 | ] | 18 | ] |
1 | -from django.shortcuts import render | 1 | +import os |
2 | +import re | ||
3 | +from urllib import parse | ||
2 | 4 | ||
3 | -# Create your views here. | 5 | +from rest_framework.generics import CreateAPIView, RetrieveAPIView, UpdateAPIView, ListAPIView |
6 | +from rest_framework.views import APIView | ||
7 | +from rest_framework.permissions import IsAuthenticated, IsAdminUser | ||
8 | +from rest_framework import status | ||
9 | +import pyexcel as p | ||
10 | +from django.db import transaction | ||
11 | +from django.forms import model_to_dict | ||
12 | +from django.db.models import Q | ||
13 | + | ||
14 | +from .models import SKU, Auditor, Flow, FlowSKU, Result, Leader | ||
15 | +from wxProject.settings import MEDIA_ROOT | ||
16 | +from utils.pagination import MyPageNumberPagination | ||
17 | +from wxProject.qywx_settings import Conf, sku_conf | ||
18 | +from utils.util import response | ||
19 | +from utils.media import upload_media | ||
20 | +from .serializers import FlowSerializer, SKUSerializer, FlowListSerializer, FlowSKUSerializer | ||
21 | +from utils.helpers import WxPushHelper | ||
22 | + | ||
23 | + | ||
24 | +class CreateSKUFlow(CreateAPIView): | ||
25 | + """ 创建SKU审核流程 """ | ||
26 | + serializer_class = FlowSerializer | ||
27 | + permission_classes = (IsAuthenticated,) | ||
28 | + | ||
29 | + # @transaction.atomic | ||
30 | + def post(self, request, *args, **kwargs): | ||
31 | + super(CreateSKUFlow, self).__init__() | ||
32 | + skus = request.data.get('sku', None) | ||
33 | + if not skus or skus == []: | ||
34 | + return response(msg=u"sku不能为空", status_code=status.HTTP_400_BAD_REQUEST) | ||
35 | + # 提交过来sku的ID | ||
36 | + # flow 表 flow_sku表 result表 | ||
37 | + wx_client = WxPushHelper(Conf[sku_conf['APP_ID']]) | ||
38 | + with transaction.atomic(): | ||
39 | + save_id = transaction.savepoint() | ||
40 | + | ||
41 | + try: | ||
42 | + skus = list(set(skus)) | ||
43 | + sku_objs = SKU.objects.filter(pk__in=skus) | ||
44 | + flow = Flow.objects.create(starter=request.user) | ||
45 | + flow_sku_list = [FlowSKU(sku=sku, flow=flow) for sku in sku_objs] | ||
46 | + FlowSKU.objects.bulk_create(flow_sku_list) | ||
47 | + auditors = Auditor.objects.all().order_by('order') | ||
48 | + auditor_list = [Result(auditor=auditor, flow=flow) for auditor in auditors] | ||
49 | + Result.objects.bulk_create(auditor_list) | ||
50 | + | ||
51 | + transaction.savepoint_commit(save_id) | ||
52 | + | ||
53 | + url = re.sub("PK", str(flow.id), sku_conf['flow_detail']) | ||
54 | + url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), sku_conf['wx_authorize']) | ||
55 | + first_auditor = auditors[0] | ||
56 | + | ||
57 | + wx_client.push_card(first_auditor.user.wx_token, url, f"{request.user.username}发起一个毛利不达标产品审批流程") | ||
58 | + wx_client.push_card(request.user.wx_token, url, u"流程创建成功") | ||
59 | + # 通知创建人和审批人 | ||
60 | + return response() | ||
61 | + except Exception as e: | ||
62 | + print(e.args) | ||
63 | + print(e.with_traceback) | ||
64 | + transaction.savepoint_rollback(save_id) | ||
65 | + return response(msg=u"创建流程有误", status_code=status.HTTP_400_BAD_REQUEST) | ||
66 | + | ||
67 | + | ||
68 | +class UpdateSKUInfo(UpdateAPIView): | ||
69 | + queryset = SKU.objects.all() | ||
70 | + serializer_class = SKUSerializer | ||
71 | + permission_classes = (IsAuthenticated,) | ||
72 | + | ||
73 | + def put(self, request, *args, **kwargs): | ||
74 | + """ 更新 单个sku的信息 """ | ||
75 | + serializer = SKUSerializer(data=request.data) | ||
76 | + # 查找对应用户是否拥有该sku的修改权 | ||
77 | + flow_id = request.data.get('flowID', None) | ||
78 | + if not flow_id: | ||
79 | + return response(msg=u"非法参数", status_code=status.HTTP_400_BAD_REQUEST) | ||
80 | + flow_sku = FlowSKU.objects.filter(flow_id=flow_id, sku_id=kwargs['pk']).first() | ||
81 | + if not flow_sku or flow_sku.flow.starter.id != request.user.id: | ||
82 | + return response(msg=u"非法参数", status_code=status.HTTP_401_UNAUTHORIZED) | ||
83 | + | ||
84 | + if not serializer.is_valid(): | ||
85 | + raise ValueError(serializer.errors) | ||
86 | + else: | ||
87 | + serializer.update(instance=self.get_object(), validated_data=serializer.data) | ||
88 | + return response() | ||
89 | + | ||
90 | + | ||
91 | +class FlowDetail(RetrieveAPIView): | ||
92 | + """ 查看当前流程 """ | ||
93 | + # 查看当前流程的sku列表 流程进度 流程结果 | ||
94 | + queryset = Flow.objects.all() | ||
95 | + serializer_class = FlowSerializer | ||
96 | + permission_classes = (IsAuthenticated,) | ||
97 | + | ||
98 | + def get(self, request, *args, **kwargs): | ||
99 | + cur_obj = self.get_object() | ||
100 | + cur_obj.result = [] | ||
101 | + results = Result.objects.filter(flow=cur_obj) | ||
102 | + for i in results: | ||
103 | + cur_obj.result.append({ | ||
104 | + "auditor": i.auditor.user.username, | ||
105 | + "is_accept": i.is_accept, | ||
106 | + "memo": i.memo, | ||
107 | + }) | ||
108 | + # skus = (SKU.objects.filter(pk__in=FlowSKU.objects.filter(flow=cur_obj).values_list('sku_id', flat=True))) | ||
109 | + # cur_obj.skus = [model_to_dict(sku) for sku in skus] | ||
110 | + flow_skus = FlowSKU.objects.filter(flow=cur_obj) | ||
111 | + cur_obj.skus = [FlowSKUSerializer(sku).data for sku in flow_skus] | ||
112 | + | ||
113 | + return response(FlowSerializer(cur_obj).data) | ||
114 | + | ||
115 | + | ||
116 | +class AuditFlow(UpdateAPIView): | ||
117 | + """ 更新当前流程状态,对流程进行审批""" | ||
118 | + queryset = Flow.objects.all() | ||
119 | + serializer_class = FlowSerializer | ||
120 | + permission_classes = (IsAuthenticated, IsAdminUser) | ||
121 | + | ||
122 | + @staticmethod | ||
123 | + def _check_audit(flow_obj): | ||
124 | + # 查看是否已经全部审核完毕 进行更新flow表,只有所有sku都审批通过才能流向下一节点 | ||
125 | + # 所有的审核人员, 是否有result记录 | ||
126 | + aud_result_len = Result.objects.filter(flow=flow_obj, is_accept__isnull=False).count() | ||
127 | + auditor_len = Auditor.objects.count() | ||
128 | + return aud_result_len == auditor_len | ||
129 | + | ||
130 | + @transaction.atomic | ||
131 | + def partial_update(self, request, *args, **kwargs): | ||
132 | + # 对项目进行更新 | ||
133 | + | ||
134 | + accept_choices = ( | ||
135 | + ('accept', '通过'), | ||
136 | + ('reject', '否决') | ||
137 | + ) | ||
138 | + # accept_param = accept_choices[0][0] if request.data.get('is_accept') else accept_choices[1][0] | ||
139 | + skus = request.data.get('sku', []) | ||
140 | + if len(skus) == 0 or not isinstance(request.data.get('is_accept'), bool): | ||
141 | + return response(msg=u"非法审批参数", status_code=status.HTTP_400_BAD_REQUEST) | ||
142 | + | ||
143 | + result_obj = Result.objects.filter(auditor_id=self.request.user.id, is_accept__isnull=True, | ||
144 | + flow__pk=kwargs['pk']).first() | ||
145 | + obj = self.get_object() | ||
146 | + if not obj or not result_obj: | ||
147 | + raise PermissionError | ||
148 | + else: | ||
149 | + # 只有当前flow的所有的sku审批通过,采流下一节点审批 | ||
150 | + flow_skus = FlowSKU.objects.filter(flow=obj) | ||
151 | + accept_bool = bool(request.data.get('is_accept')) | ||
152 | + if len(flow_skus) == len(request.data.get('sku')): | ||
153 | + accept_param = accept_choices[0][0] | ||
154 | + else: | ||
155 | + obj.is_done = True | ||
156 | + accept_param = accept_choices[1][0] | ||
157 | + result_obj.is_accept = accept_param | ||
158 | + result_obj.memo = request.data.get('memo', '') | ||
159 | + result_obj.save() | ||
160 | + for flow_sku in flow_skus: | ||
161 | + if flow_sku.sku.id in skus: | ||
162 | + flow_sku.is_pass = accept_bool | ||
163 | + else: | ||
164 | + flow_sku.is_pass = not accept_bool | ||
165 | + flow_sku.save() | ||
166 | + | ||
167 | + wx_client = WxPushHelper(Conf[sku_conf['APP_ID']]) | ||
168 | + full_audit_done = self._check_audit(obj) | ||
169 | + url = re.sub("PK", str(obj.id), sku_conf['flow_detail']) | ||
170 | + url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), sku_conf['wx_authorize']) | ||
171 | + desc = "返单特采流程所有审批已完成" if full_audit_done else f"{request.user.username}已审批完成" | ||
172 | + if full_audit_done: | ||
173 | + obj.is_done = True | ||
174 | + else: | ||
175 | + if not bool(request.data.get('is_accept')): | ||
176 | + obj.is_done = True | ||
177 | + else: | ||
178 | + next_auditor_id = Result.objects.filter(flow=obj, is_accept__isnull=True) \ | ||
179 | + .values_list('auditor_id', flat=True).order_by('pk').first() | ||
180 | + second_auditor = Auditor.objects.filter(pk=next_auditor_id).first() | ||
181 | + wx_client.push_card(second_auditor.user.wx_token, url, f"{request.user.username}已审核了一个返单特采申请") | ||
182 | + obj.save() | ||
183 | + wx_client.push_card(obj.starter.wx_token, url, desc) | ||
184 | + | ||
185 | + return response(FlowSerializer(obj).data) | ||
186 | + | ||
187 | + | ||
188 | +class AuditFlowList(ListAPIView): | ||
189 | + """ 查看当前审核人员名下的审核清单 """ | ||
190 | + queryset = Result.objects.all() | ||
191 | + serializer_class = FlowListSerializer | ||
192 | + pagination_class = MyPageNumberPagination | ||
193 | + permission_classes = (IsAuthenticated,) | ||
194 | + | ||
195 | + def get_queryset(self): | ||
196 | + data = Result.objects.filter(auditor_id=self.request.user.id).order_by('is_accept', '-create_time') | ||
197 | + for item in data: | ||
198 | + # result = Flow.objects.filter(=self.request.user).values_list('is_done', flat=True).first() | ||
199 | + item.creator_name = item.flow.starter.username | ||
200 | + item.result = True if item.is_accept else False | ||
201 | + item.flow_id = item.flow.id | ||
202 | + return data | ||
203 | + | ||
204 | + | ||
205 | +class CheckAuth(APIView): | ||
206 | + """ 查看当前查看用户是否有审批权限""" | ||
207 | + allowed_methods = ('GET',) | ||
208 | + permission_classes = (IsAuthenticated,) | ||
209 | + | ||
210 | + @staticmethod | ||
211 | + def get(request, *args, **kwargs): | ||
212 | + flow_result = Result.objects.filter(flow__pk=kwargs['pk']) | ||
213 | + # auditor=request.user) | Q(flow__starter=request.user) | ||
214 | + if not flow_result \ | ||
215 | + or flow_result.result_auditor.user.id != request.user.id: | ||
216 | + return response(False) | ||
217 | + else: | ||
218 | + order = int(Auditor.objects.filter(user=request.user).values_list('order', flat=True).first()) | ||
219 | + if order > 0: | ||
220 | + # 当审核人员排队时 需要判断是否已经流转到自己 前一个人员是否已经有处理 | ||
221 | + # 还要判断自己是否已经审核过了 | ||
222 | + index = order - 1 | ||
223 | + if bool(flow_result[index].is_accept) and not bool(flow_result[order].is_accept): | ||
224 | + return response(True) | ||
225 | + else: | ||
226 | + return response(False) | ||
227 | + else: | ||
228 | + return response(False) if bool(flow_result[0].is_accept) else response(True) | ||
229 | + | ||
230 | + | ||
231 | +class ParseSKUExcel(CreateAPIView): | ||
232 | + """ 解析上传excel的SKU数据""" | ||
233 | + serializer_class = SKUSerializer | ||
234 | + permission_classes = (IsAuthenticated,) | ||
235 | + allowed_extension = (".xls", ".xlsx") | ||
236 | + | ||
237 | + def post(self, request, *args, **kwargs): | ||
238 | + super(ParseSKUExcel, self).__init__() | ||
239 | + file_obj = self._upload(request) | ||
240 | + # 解析sku列表 插入数据库 | ||
241 | + path = os.path.join(MEDIA_ROOT, str(file_obj.file)) | ||
242 | + t = p.get_sheet(file_name=path, start_row=1, column_limit=16) | ||
243 | + with transaction.atomic(): | ||
244 | + save_id = transaction.savepoint() | ||
245 | + try: | ||
246 | + s_list = self._insert_data(list(t.rows())) | ||
247 | + transaction.savepoint_commit(save_id) | ||
248 | + return response(s_list) | ||
249 | + except ValueError as e: | ||
250 | + transaction.savepoint_rollback(save_id) | ||
251 | + return response(msg=u"文件上传数据有误", status_code=status.HTTP_400_BAD_REQUEST) | ||
252 | + except IndexError as e: | ||
253 | + transaction.savepoint_rollback(save_id) | ||
254 | + return response(msg=u"文件上传数据有误", status_code=status.HTTP_400_BAD_REQUEST) | ||
255 | + except Exception as e: | ||
256 | + transaction.savepoint_rollback(save_id) | ||
257 | + return response(msg=u"文件上传数据有误", status_code=status.HTTP_400_BAD_REQUEST) | ||
258 | + | ||
259 | + @staticmethod | ||
260 | + def _insert_data(rows): | ||
261 | + obj_list = [] | ||
262 | + for row in rows: | ||
263 | + if len(row) < 16: | ||
264 | + raise IndexError("上传数据字段不完整") | ||
265 | + qty = 0 if row[5] == "" or row[5] == "#N/A" else int(row[5]) | ||
266 | + price_with_tax = 0 if row[6] == "" or row[6] == "#N/A" else float(row[6]) | ||
267 | + amount_with_tax = 0 if row[7] == "" or row[7] == "#N/A" else float(row[7]) | ||
268 | + sell_day = 0 if row[8] == "" or row[8] == "#N/A" else int(row[8]) | ||
269 | + qty_within_30 = 0 if row[9] == "" or row[9] == "#N/A" else int(row[9]) | ||
270 | + inventory = 0 if row[10] == "" or row[10] == "#N/A" else int(row[10]) | ||
271 | + coming_inventory = 0 if row[11] == "" or row[11] == "#N/A" else int(row[11]) | ||
272 | + gross_profit_rate = 0 if row[12] == "" or row[12] == "#N/A" else float(row[12]) | ||
273 | + return_rate = 0 if row[13] == "" or row[13] == "#N/A" else float(row[13]) | ||
274 | + memo = "" if row[14] == "#N/A" else row[14].strip() | ||
275 | + purchaser = row[15].strip() | ||
276 | + | ||
277 | + obj = SKU.objects.create( | ||
278 | + supplier=row[0], | ||
279 | + sku=row[1], | ||
280 | + model=row[2], | ||
281 | + title=row[3], | ||
282 | + is_new=row[4], | ||
283 | + qty=qty, | ||
284 | + price_with_tax=price_with_tax, | ||
285 | + amount_with_tax=amount_with_tax, | ||
286 | + sell_day=sell_day, | ||
287 | + qty_within_30=qty_within_30, | ||
288 | + inventory=inventory, | ||
289 | + coming_inventory=coming_inventory, | ||
290 | + gross_profit_rate=gross_profit_rate, | ||
291 | + return_rate=return_rate, | ||
292 | + memo=memo, | ||
293 | + purchaser=purchaser, | ||
294 | + | ||
295 | + ) | ||
296 | + obj_list.append(SKUSerializer(obj).data) | ||
297 | + return obj_list | ||
298 | + | ||
299 | + def _upload(self, request): | ||
300 | + excel = request.FILES.get('file') | ||
301 | + | ||
302 | + if not excel: | ||
303 | + return response(msg=u"文件上传失败", status_code=status.HTTP_400_BAD_REQUEST) | ||
304 | + excel.name = excel.name.strip('"') | ||
305 | + ext_pos = excel.name.rfind('.') | ||
306 | + uploaded_file_ext = excel.name[ext_pos:] | ||
307 | + if uploaded_file_ext not in self.allowed_extension: | ||
308 | + return response(msg="非法文件类型", status_code=status.HTTP_400_BAD_REQUEST) | ||
309 | + return upload_media(excel, uploaded_file_ext, request.user) |
@@ -59,7 +59,7 @@ class WxPushHelper: | @@ -59,7 +59,7 @@ class WxPushHelper: | ||
59 | "msgtype": "textcard", | 59 | "msgtype": "textcard", |
60 | "agentid": self.conf['APP_ID'], # 企业应用ID | 60 | "agentid": self.conf['APP_ID'], # 企业应用ID |
61 | "textcard": { | 61 | "textcard": { |
62 | - "title": "产品立项流程通知", | 62 | + "title": f"{self.conf['title']}流程通知", |
63 | "description": description, | 63 | "description": description, |
64 | "url": url, | 64 | "url": url, |
65 | "btntxt": "点击查看" | 65 | "btntxt": "点击查看" |
@@ -15,21 +15,8 @@ from rest_framework.permissions import IsAuthenticated, AllowAny | @@ -15,21 +15,8 @@ from rest_framework.permissions import IsAuthenticated, AllowAny | ||
15 | from rest_framework import status | 15 | from rest_framework import status |
16 | 16 | ||
17 | 17 | ||
18 | -class UploadMedia(CreateAPIView): | ||
19 | - serializer_class = MediaSerializer | ||
20 | - permission_classes = (IsAuthenticated, ) | ||
21 | - | ||
22 | - def post(self, request, *args, **kwargs): | ||
23 | - super(UploadMedia, self).__init__() | ||
24 | - uploaded_file = request.FILES.get('file') | ||
25 | - uploaded_file.name = uploaded_file.name.strip('"') | ||
26 | - | ||
27 | - if not uploaded_file: | ||
28 | - return response(msg=u"文件上传失败", status_code=status.HTTP_400_BAD_REQUEST) | ||
29 | - ext_pos = uploaded_file.name.rfind('.') | ||
30 | - uploaded_file_ext = uploaded_file.name[ext_pos:] | ||
31 | - if not self.allowed_extension(uploaded_file_ext): | ||
32 | - return response(msg="非法文件类型", status_code=status.HTTP_400_BAD_REQUEST) | 18 | +def upload_media(uploaded_file, uploaded_file_ext, user): |
19 | + """ 处理上传新建媒体记录 """ | ||
33 | hash_file_name = uuid() + uploaded_file_ext | 20 | hash_file_name = uuid() + uploaded_file_ext |
34 | time_tag = time.strftime('%Y-%m-%d') | 21 | time_tag = time.strftime('%Y-%m-%d') |
35 | file_path = time_tag + os.sep + hash_file_name | 22 | file_path = time_tag + os.sep + hash_file_name |
@@ -48,17 +35,35 @@ class UploadMedia(CreateAPIView): | @@ -48,17 +35,35 @@ class UploadMedia(CreateAPIView): | ||
48 | file=uploaded_file, | 35 | file=uploaded_file, |
49 | file_name=uploaded_file.name, | 36 | file_name=uploaded_file.name, |
50 | hash=file_hash, | 37 | hash=file_hash, |
51 | - user=request.user, | 38 | + user=user, |
52 | size=file_size, | 39 | size=file_size, |
53 | extension=uploaded_file_ext | 40 | extension=uploaded_file_ext |
54 | ) | 41 | ) |
55 | os.remove(os.path.join(MEDIA_ROOT, file_path)) | 42 | os.remove(os.path.join(MEDIA_ROOT, file_path)) |
56 | - # return response.Response(MediaSerializer(file, context={'request': request}).data) | 43 | + return file |
44 | + | ||
45 | + | ||
46 | +class UploadMedia(CreateAPIView): | ||
47 | + serializer_class = MediaSerializer | ||
48 | + permission_classes = (IsAuthenticated, ) | ||
49 | + | ||
50 | + def post(self, request, *args, **kwargs): | ||
51 | + super(UploadMedia, self).__init__() | ||
52 | + uploaded_file = request.FILES.get('file') | ||
53 | + uploaded_file.name = uploaded_file.name.strip('"') | ||
54 | + | ||
55 | + if not uploaded_file: | ||
56 | + return response(msg=u"文件上传失败", status_code=status.HTTP_400_BAD_REQUEST) | ||
57 | + ext_pos = uploaded_file.name.rfind('.') | ||
58 | + uploaded_file_ext = uploaded_file.name[ext_pos:] | ||
59 | + if not self.allowed_extension(uploaded_file_ext): | ||
60 | + return response(msg="非法文件类型", status_code=status.HTTP_400_BAD_REQUEST) | ||
61 | + file = upload_media(uploaded_file, uploaded_file_ext, request.user) | ||
57 | return response(MediaSerializer(file, context={'request': request}).data) | 62 | return response(MediaSerializer(file, context={'request': request}).data) |
58 | 63 | ||
59 | @staticmethod | 64 | @staticmethod |
60 | - def allowed_extension(ext): | ||
61 | - choices = UPLOAD_MEDIA_CHOICES | 65 | + def allowed_extension(ext, allowed_ext=None): |
66 | + choices = allowed_ext if allowed_ext else UPLOAD_MEDIA_CHOICES | ||
62 | for allowed_ext in choices: | 67 | for allowed_ext in choices: |
63 | if ext == allowed_ext[0]: | 68 | if ext == allowed_ext[0]: |
64 | return True | 69 | return True |
@@ -11,13 +11,17 @@ project_conf = { | @@ -11,13 +11,17 @@ project_conf = { | ||
11 | "CORP_ID": "ww0f3efc2873ad11c3", | 11 | "CORP_ID": "ww0f3efc2873ad11c3", |
12 | "APP_ID": '1000078', | 12 | "APP_ID": '1000078', |
13 | "APP_SECRET": "7MHpdQICiegx9rIc4iZrEPunb1aYUqdJYKSW9v7a1A8", | 13 | "APP_SECRET": "7MHpdQICiegx9rIc4iZrEPunb1aYUqdJYKSW9v7a1A8", |
14 | + "wx_authorize": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww0f3efc2873ad11c3&redirect_uri=REDIRECT_URL&response_type=code&scope=snsapi_base&state=1000078#wechat_redirect", | ||
15 | + "flow_detail": "http://project.tacklifetools.com/product/audit/PK" | ||
14 | } | 16 | } |
15 | 17 | ||
16 | sku_conf = { | 18 | sku_conf = { |
17 | - "title": "sku条目审批应用", | 19 | + "title": "返单特采", |
18 | "CORP_ID": "ww0f3efc2873ad11c3", | 20 | "CORP_ID": "ww0f3efc2873ad11c3", |
19 | "APP_ID": '1000081', | 21 | "APP_ID": '1000081', |
20 | "APP_SECRET": "_O_MrxbQO1vojzNBPAiaF_MdzikHRbnVfFc3v8iOtKo", | 22 | "APP_SECRET": "_O_MrxbQO1vojzNBPAiaF_MdzikHRbnVfFc3v8iOtKo", |
23 | + "wx_authorize": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww0f3efc2873ad11c3&redirect_uri=REDIRECT_URL&response_type=code&scope=snsapi_base&state=1000081#wechat_redirect", | ||
24 | + "flow_detail": "http://project.tacklifetools.com/sku/audit/PK" | ||
21 | } | 25 | } |
22 | 26 | ||
23 | 27 | ||
@@ -25,3 +29,4 @@ Conf = { | @@ -25,3 +29,4 @@ Conf = { | ||
25 | "1000078": project_conf, | 29 | "1000078": project_conf, |
26 | "1000081": sku_conf | 30 | "1000081": sku_conf |
27 | } | 31 | } |
32 | + |
@@ -177,7 +177,3 @@ SIMPLE_JWT = { | @@ -177,7 +177,3 @@ SIMPLE_JWT = { | ||
177 | 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), | 177 | 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1), |
178 | } | 178 | } |
179 | 179 | ||
180 | -FRONT_URL = { | ||
181 | - "wx_authorize": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww0f3efc2873ad11c3&redirect_uri=REDIRECT_URL&response_type=code&scope=snsapi_base#wechat_redirect", | ||
182 | - "flow_detail": "http://project.tacklifetools.com/product/audit/PK" | ||
183 | -} |
@@ -18,6 +18,7 @@ urlpatterns = [ | @@ -18,6 +18,7 @@ urlpatterns = [ | ||
18 | path(api_version + 'auth/', include('usercenter.urls', namespace='usercenter')), | 18 | path(api_version + 'auth/', include('usercenter.urls', namespace='usercenter')), |
19 | path(api_version + 'upload/', UploadMedia.as_view()), | 19 | path(api_version + 'upload/', UploadMedia.as_view()), |
20 | path(api_version + 'project/', include('project.urls', namespace="project")), | 20 | path(api_version + 'project/', include('project.urls', namespace="project")), |
21 | + path(api_version + 'sku/', include('sku.urls', namespace="sku")), | ||
21 | path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), | 22 | path('api-auth/', include('rest_framework.urls', namespace='rest_framework')), |
22 | re_path(r'api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), | 23 | re_path(r'api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'), |
23 | re_path(r'api/token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'), | 24 | re_path(r'api/token/', MyTokenObtainPairView.as_view(), name='token_obtain_pair'), |
-
请 注册 或 登录 后发表评论