views.py
11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
import os
import re
from urllib import parse
from rest_framework.generics import CreateAPIView, RetrieveAPIView, UpdateAPIView, ListAPIView
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from rest_framework import status
import pyexcel as p
from django.db import transaction
from django.forms import model_to_dict
from django.db.models import Q
from .models import SKU, Auditor, Flow, FlowSKU, Result, Leader
from wxProject.settings import MEDIA_ROOT
from utils.pagination import MyPageNumberPagination
from wxProject.qywx_settings import Conf, sku_conf
from utils.util import response
from utils.media import upload_media
from .serializers import FlowSerializer, SKUSerializer, FlowListSerializer, FlowSKUSerializer
from utils.helpers import WxPushHelper
class CreateSKUFlow(CreateAPIView):
""" 创建SKU审核流程 """
serializer_class = FlowSerializer
permission_classes = (IsAuthenticated,)
# @transaction.atomic
def post(self, request, *args, **kwargs):
super(CreateSKUFlow, self).__init__()
skus = request.data.get('sku', None)
if not skus or skus == []:
return response(msg=u"sku不能为空", status_code=status.HTTP_400_BAD_REQUEST)
# 提交过来sku的ID
# flow 表 flow_sku表 result表
wx_client = WxPushHelper(Conf[sku_conf['APP_ID']])
with transaction.atomic():
save_id = transaction.savepoint()
try:
skus = list(set(skus))
sku_objs = SKU.objects.filter(pk__in=skus)
flow = Flow.objects.create(starter=request.user)
flow_sku_list = [FlowSKU(sku=sku, flow=flow) for sku in sku_objs]
FlowSKU.objects.bulk_create(flow_sku_list)
auditors = Auditor.objects.all().order_by('order')
auditor_list = [Result(auditor=auditor, flow=flow) for auditor in auditors]
Result.objects.bulk_create(auditor_list)
transaction.savepoint_commit(save_id)
url = re.sub("PK", str(flow.id), sku_conf['flow_detail'])
url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), sku_conf['wx_authorize'])
first_auditor = auditors[0]
wx_client.push_card(first_auditor.user.wx_token, url, f"{request.user.username}发起一个毛利不达标产品审批流程")
wx_client.push_card(request.user.wx_token, url, u"流程创建成功")
# 通知创建人和审批人
return response()
except Exception as e:
print(e.args)
print(e.with_traceback)
transaction.savepoint_rollback(save_id)
return response(msg=u"创建流程有误", status_code=status.HTTP_400_BAD_REQUEST)
class UpdateSKUInfo(UpdateAPIView):
queryset = SKU.objects.all()
serializer_class = SKUSerializer
permission_classes = (IsAuthenticated,)
def put(self, request, *args, **kwargs):
""" 更新 单个sku的信息 """
serializer = SKUSerializer(data=request.data)
# 查找对应用户是否拥有该sku的修改权
flow_id = request.data.get('flowID', None)
if not flow_id:
return response(msg=u"非法参数", status_code=status.HTTP_400_BAD_REQUEST)
flow_sku = FlowSKU.objects.filter(flow_id=flow_id, sku_id=kwargs['pk']).first()
if not flow_sku or flow_sku.flow.starter.id != request.user.id:
return response(msg=u"非法参数", status_code=status.HTTP_401_UNAUTHORIZED)
if not serializer.is_valid():
raise ValueError(serializer.errors)
else:
serializer.update(instance=self.get_object(), validated_data=serializer.data)
return response()
class FlowDetail(RetrieveAPIView):
""" 查看当前流程 """
# 查看当前流程的sku列表 流程进度 流程结果
queryset = Flow.objects.all()
serializer_class = FlowSerializer
permission_classes = (IsAuthenticated,)
def get(self, request, *args, **kwargs):
cur_obj = self.get_object()
cur_obj.result = []
results = Result.objects.filter(flow=cur_obj)
for i in results:
cur_obj.result.append({
"auditor": i.auditor.user.username,
"is_accept": i.is_accept,
"memo": i.memo,
})
# skus = (SKU.objects.filter(pk__in=FlowSKU.objects.filter(flow=cur_obj).values_list('sku_id', flat=True)))
# cur_obj.skus = [model_to_dict(sku) for sku in skus]
flow_skus = FlowSKU.objects.filter(flow=cur_obj)
cur_obj.skus = [FlowSKUSerializer(sku).data for sku in flow_skus]
return response(FlowSerializer(cur_obj).data)
class AuditFlow(UpdateAPIView):
""" 更新当前流程状态,对流程进行审批"""
queryset = Flow.objects.all()
serializer_class = FlowSerializer
permission_classes = (IsAuthenticated, IsAdminUser)
@staticmethod
def _check_audit(flow_obj):
# 查看是否已经全部审核完毕 进行更新flow表,只有所有sku都审批通过才能流向下一节点
# 所有的审核人员, 是否有result记录
aud_result_len = Result.objects.filter(flow=flow_obj, is_accept__isnull=False).count()
auditor_len = Auditor.objects.count()
return aud_result_len == auditor_len
@transaction.atomic
def partial_update(self, request, *args, **kwargs):
# 对项目进行更新
accept_choices = (
('accept', '通过'),
('reject', '否决')
)
# accept_param = accept_choices[0][0] if request.data.get('is_accept') else accept_choices[1][0]
skus = request.data.get('sku', [])
if len(skus) == 0 or not isinstance(request.data.get('is_accept'), bool):
return response(msg=u"非法审批参数", status_code=status.HTTP_400_BAD_REQUEST)
result_obj = Result.objects.filter(auditor_id=self.request.user.id, is_accept__isnull=True,
flow__pk=kwargs['pk']).first()
obj = self.get_object()
if not obj or not result_obj:
raise PermissionError
else:
# 只有当前flow的所有的sku审批通过,采流下一节点审批
flow_skus = FlowSKU.objects.filter(flow=obj)
accept_bool = bool(request.data.get('is_accept'))
if len(flow_skus) == len(request.data.get('sku')):
accept_param = accept_choices[0][0]
else:
obj.is_done = True
accept_param = accept_choices[1][0]
result_obj.is_accept = accept_param
result_obj.memo = request.data.get('memo', '')
result_obj.save()
for flow_sku in flow_skus:
if flow_sku.sku.id in skus:
flow_sku.is_pass = accept_bool
else:
flow_sku.is_pass = not accept_bool
flow_sku.save()
wx_client = WxPushHelper(Conf[sku_conf['APP_ID']])
full_audit_done = self._check_audit(obj)
url = re.sub("PK", str(obj.id), sku_conf['flow_detail'])
url = re.sub("REDIRECT_URL", parse.quote(url, safe=''), sku_conf['wx_authorize'])
desc = "返单特采流程所有审批已完成" if full_audit_done else f"{request.user.username}已审批完成"
if full_audit_done:
obj.is_done = True
else:
if not bool(request.data.get('is_accept')):
obj.is_done = True
else:
next_auditor_id = Result.objects.filter(flow=obj, is_accept__isnull=True) \
.values_list('auditor_id', flat=True).order_by('pk').first()
second_auditor = Auditor.objects.filter(pk=next_auditor_id).first()
wx_client.push_card(second_auditor.user.wx_token, url, f"{request.user.username}已审核了一个返单特采申请")
obj.save()
wx_client.push_card(obj.starter.wx_token, url, desc)
return response(FlowSerializer(obj).data)
class AuditFlowList(ListAPIView):
""" 查看当前审核人员名下的审核清单 """
queryset = Result.objects.all()
serializer_class = FlowListSerializer
pagination_class = MyPageNumberPagination
permission_classes = (IsAuthenticated,)
def get_queryset(self):
data = Result.objects.filter(auditor_id=self.request.user.id).order_by('is_accept', '-create_time')
for item in data:
# result = Flow.objects.filter(=self.request.user).values_list('is_done', flat=True).first()
item.creator_name = item.flow.starter.username
item.result = True if item.is_accept else False
item.flow_id = item.flow.id
return data
class CheckAuth(APIView):
""" 查看当前查看用户是否有审批权限"""
allowed_methods = ('GET',)
permission_classes = (IsAuthenticated,)
@staticmethod
def get(request, *args, **kwargs):
flow_result = Result.objects.filter(flow__pk=kwargs['pk'])
# auditor=request.user) | Q(flow__starter=request.user)
if not flow_result \
or flow_result.result_auditor.user.id != request.user.id:
return response(False)
else:
order = int(Auditor.objects.filter(user=request.user).values_list('order', flat=True).first())
if order > 0:
# 当审核人员排队时 需要判断是否已经流转到自己 前一个人员是否已经有处理
# 还要判断自己是否已经审核过了
index = order - 1
if bool(flow_result[index].is_accept) and not bool(flow_result[order].is_accept):
return response(True)
else:
return response(False)
else:
return response(False) if bool(flow_result[0].is_accept) else response(True)
class ParseSKUExcel(CreateAPIView):
""" 解析上传excel的SKU数据"""
serializer_class = SKUSerializer
permission_classes = (IsAuthenticated,)
allowed_extension = (".xls", ".xlsx")
def post(self, request, *args, **kwargs):
super(ParseSKUExcel, self).__init__()
file_obj = self._upload(request)
# 解析sku列表 插入数据库
path = os.path.join(MEDIA_ROOT, str(file_obj.file))
t = p.get_sheet(file_name=path, start_row=1, column_limit=16)
with transaction.atomic():
save_id = transaction.savepoint()
try:
s_list = self._insert_data(list(t.rows()))
transaction.savepoint_commit(save_id)
return response(s_list)
except ValueError as e:
transaction.savepoint_rollback(save_id)
return response(msg=u"文件上传数据有误", status_code=status.HTTP_400_BAD_REQUEST)
except IndexError as e:
transaction.savepoint_rollback(save_id)
return response(msg=u"文件上传数据有误", status_code=status.HTTP_400_BAD_REQUEST)
except Exception as e:
transaction.savepoint_rollback(save_id)
return response(msg=u"文件上传数据有误", status_code=status.HTTP_400_BAD_REQUEST)
@staticmethod
def _insert_data(rows):
obj_list = []
for row in rows:
if len(row) < 16:
raise IndexError("上传数据字段不完整")
qty = 0 if row[5] == "" or row[5] == "#N/A" else int(row[5])
price_with_tax = 0 if row[6] == "" or row[6] == "#N/A" else float(row[6])
amount_with_tax = 0 if row[7] == "" or row[7] == "#N/A" else float(row[7])
sell_day = 0 if row[8] == "" or row[8] == "#N/A" else int(row[8])
qty_within_30 = 0 if row[9] == "" or row[9] == "#N/A" else int(row[9])
inventory = 0 if row[10] == "" or row[10] == "#N/A" else int(row[10])
coming_inventory = 0 if row[11] == "" or row[11] == "#N/A" else int(row[11])
gross_profit_rate = 0 if row[12] == "" or row[12] == "#N/A" else float(row[12])
return_rate = 0 if row[13] == "" or row[13] == "#N/A" else float(row[13])
memo = "" if row[14] == "#N/A" else row[14].strip()
purchaser = row[15].strip()
obj = SKU.objects.create(
supplier=row[0],
sku=row[1],
model=row[2],
title=row[3],
is_new=row[4],
qty=qty,
price_with_tax=price_with_tax,
amount_with_tax=amount_with_tax,
sell_day=sell_day,
qty_within_30=qty_within_30,
inventory=inventory,
coming_inventory=coming_inventory,
gross_profit_rate=gross_profit_rate,
return_rate=return_rate,
memo=memo,
purchaser=purchaser,
)
obj_list.append(SKUSerializer(obj).data)
return obj_list
def _upload(self, request):
excel = request.FILES.get('file')
if not excel:
return response(msg=u"文件上传失败", status_code=status.HTTP_400_BAD_REQUEST)
excel.name = excel.name.strip('"')
ext_pos = excel.name.rfind('.')
uploaded_file_ext = excel.name[ext_pos:]
if uploaded_file_ext not in self.allowed_extension:
return response(msg="非法文件类型", status_code=status.HTTP_400_BAD_REQUEST)
return upload_media(excel, uploaded_file_ext, request.user)