|
|
from django.shortcuts import render
|
|
|
import os
|
|
|
import re
|
|
|
from urllib import parse
|
|
|
|
|
|
# Create your views here. |
|
|
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) |
...
|
...
|
|