Bladeren bron

Merge branch 'master' of http://git.zzliaoyuan.com:4000/wushaodong/decorate

lijiangwei 4 jaren geleden
bovenliggende
commit
580d069b1a

+ 21 - 6
apps/account/views.py

@@ -8,9 +8,10 @@ from rest_framework.views import APIView
 from rest_framework.serializers import ValidationError
 from utils.permission import permission_required, isLogin, check_permission
 from django.contrib.auth.models import Group, Permission
-from rest_framework_jwt.views import ObtainJSONWebToken, VerifyJSONWebToken, RefreshJSONWebToken
+from rest_framework_jwt.views import ObtainJSONWebToken, RefreshJSONWebToken
 from utils import response_error, response_ok
 from django.contrib.auth import get_user_model
+from django.utils import timezone
 
 User = get_user_model()
 from apps.account.serializers import JWTSerializer, EmployeeSerializer, GroupDictSerializer, GroupSerializer
@@ -30,23 +31,37 @@ class LoginView(ObtainJSONWebToken):
         try:
             ser = self.serializer_class(data=request.data)
             ser.request = request
-            # TODO 判断门店是否在用、在有效期内
+            # 判断门店是否在用、在有效期内
             if ser.is_valid(raise_exception=True):
+                user = User.objects.filter(id=ser.validated_data['user_id']).first()
+                store = Store.objects.filter(id=user.store_id).first()
+                if store and (store.enable == False or (store.end_date.strftime('%Y-%m-%d')) < (timezone.now().strftime('%Y-%m-%d')) ):
+                    raise CustomError(u'当前店面不可用,请联系管理员!')
                 return response_ok(ser.validated_data)
         except ValidationError as e:
             return response_error(e.detail['error'][0])
-
+        except CustomError as e:
+            return response_error(str(e))
 
 class RefreshTokenView(RefreshJSONWebToken):
+
     def post(self, request, *args, **kwargs):
         try:
             ser = self.serializer_class(data=request.data)
             if ser.is_valid(raise_exception=True):
+                user = ser.validated_data['user']
+                store = Store.objects.filter(id=user.store_id).first()
+                if store and (store.enable == False or (store.end_date.strftime('%Y-%m-%d')) < (
+                timezone.now().strftime('%Y-%m-%d')) ):
+                    raise CustomError(u'当前店面不可用,请联系管理员!')
                 return response_ok({'token': ser.validated_data['token']})
         except ValidationError as e:
-            return response_error(u'登录状态失效,请重新登录')
+            return response_ok({'error':True})
+        except CustomError as e:
+            return response_error(str(e))
 
 class ChangePassword(APIView):
+
     def post(self, request, *args, **kwargs):
         id = request.GET.get('id')
         data = json.loads(request.body)
@@ -129,7 +144,7 @@ class EmployeeViewSet(CustomModelViewSet):
     @action(methods=['post'], detail=True)
     def branch(self, request, pk):
         check_permission(request, 'account.manager_store')
-        data = json.loads(request.POST.get('sotres'))
+        data = json.loads(request.POST.get('stores'))
         try:
             with transaction.atomic():
                 instance = self.get_object()
@@ -273,7 +288,7 @@ class EmployeeTreeView(APIView):
         exist_agents = []
         manage_storess = request.user.get_manager_range()
         for store_id in manage_storess:
-            store = Store.objects.filter(id=store_id, enable=True).values('name','agent_id')
+            store = Store.objects.filter(id=store_id, check_user__isnull=False, enable=True).values('name','agent_id')
             if not store:
                 continue
             store_item = {

+ 2 - 1
apps/agent/views.py

@@ -6,6 +6,7 @@ from rest_framework.decorators import action
 from rest_framework.views import APIView
 from django.conf import settings
 from django.db import transaction
+
 from utils import response_ok, response_error
 from utils.exceptions import CustomError
 from apps.log.models import BizLog
@@ -143,7 +144,7 @@ class AgentDictView(APIView):
             stores = []
 
             for row in rows:
-                store = Store.objects.filter(agent=row, enable=True,check_user__isnull=False, end_date__gte=timezone.now().date())
+                store = Store.objects.filter(agent=row, enable=True, check_user__isnull=False, end_date__gte=timezone.now().date())
                 if request.user.store:
                     store = store.filter(id=request.user.store.id)
                 store_serializer = StoreComboboxSerializer(store, many=True).data

+ 40 - 37
apps/customer/views.py

@@ -99,6 +99,7 @@ class ReportCustomerViewSet(CustomModelViewSet):
                 # 根据分配人所在店面,创建内部跟踪提醒
                 remind_users = request.user.get_remind_users()
                 # TODO 把next_time用当前日期加上5天
+                next_time = (timezone.now() + datetime.timedelta(days=5)).strftime('%Y-%m-%d')
                 for remind_user in remind_users:
                     NewCustomerRemind.objects.create(customer=customer, next_time=next_time, remind_user_id=remind_user,
                                                      is_employee=False)
@@ -277,14 +278,14 @@ class NewCustomerViewSet(CustomModelViewSet):
                         'customer': instance,
                         'service_user': instance.track_user,
                         'store': instance.store,
+                        'notes': instance.notes,
                     }
-                    ser = Order.objects.create(**data)
-                    ser.notes = instance.notes
-                    ser.no = ser.get_no()
-                    ser.save()
+                    order = Order.objects.create(**data)
+                    order.no = order.get_no()
+                    order.save()
                     projects = instance.project.all()
                     for project in projects:
-                        ser.project.add(project.id)
+                        order.project.add(project.id)
                 # 创建订单流程,保存图片
                 user = self.request.user
                 operation = u'更新进度为:{}'.format(order.stage_progress.name)
@@ -314,19 +315,20 @@ class NewCustomerViewSet(CustomModelViewSet):
         is_copy = request.POST.get('is_copy') == '1'
 
         try:
-            instance = NewCustomer.objects.filter(id=pk).first()
+            with transaction.atomic():
+                instance = NewCustomer.objects.filter(id=pk).first()
 
-            data = {
-                'customer': instance.id,
-                'store': instance.store.id,
-                'create_user': request.user.id,
-                'description': description,
-                'is_copy': is_copy,
-            }
-            serializer = ReviewSerializer(data=data)
-            if serializer.is_valid(raise_exception=True):
-                serializer.save()
-            NewCustomerRemind.objects.filter(customer=instance, remind_user=request.user).update(next_time=next_time)
+                data = {
+                    'customer': instance.id,
+                    'store': instance.store.id,
+                    'create_user': request.user.id,
+                    'description': description,
+                    'is_copy': is_copy,
+                }
+                serializer = ReviewSerializer(data=data)
+                if serializer.is_valid(raise_exception=True):
+                    serializer.save()
+                NewCustomerRemind.objects.filter(customer=instance, remind_user=request.user).update(next_time=next_time)
 
         except ValidationError as e:
             traceback.print_exc()
@@ -382,7 +384,7 @@ class GetReviewViewSet(CustomModelViewSet):
 
     @permission_required('customer.view_new_customer')
     def filter_queryset(self, queryset):
-        # TODO 过滤记录中是否抄送业务员
+        # 过滤记录中是否抄送业务员
         if len(self.request.user.get_manager_range()) == 0:
             queryset = queryset.filter(is_copy=True)
         f = ReviewFilter(self.request.GET, queryset=queryset)
@@ -408,25 +410,26 @@ class ReviewViewSet(CustomModelViewSet):
         check_comment = request.POST.get('check_comment')
         next_time = request.POST.get('next_time')
         try:
-            instance = Review.objects.filter(id=pk).first()
-            if int(check_status) == Review.KEEPUP:
-                instance.check_user = request.user
-                instance.check_status = check_status
-                instance.check_comment = check_comment
-                instance.check_time = timezone.now()
-                instance.save()
-            if int(check_status) == Review.ABANDON:
-                instance.check_user = request.user
-                instance.check_status = check_status
-                instance.check_comment = check_comment
-                instance.check_time = timezone.now()
-                instance.save()
-                instance.customer.status = NewCustomer.ABANDONED
-                # 如果客户已下单,把工单状态改成放弃
-                Order.objects.filter(customer=instance.customer).update(status=Order.ABANDONED)
-            instance.customer.next_time = next_time
-            instance.customer.save()
-            NewCustomerRemind.objects.filter(customer=instance.customer, remind_user=instance.customer.track_user).update(next_time=next_time)
+            with transaction.atomic():
+                instance = Review.objects.filter(id=pk).first()
+                if int(check_status) == Review.KEEPUP:
+                    instance.check_user = request.user
+                    instance.check_status = check_status
+                    instance.check_comment = check_comment
+                    instance.check_time = timezone.now()
+                    instance.save()
+                if int(check_status) == Review.ABANDON:
+                    instance.check_user = request.user
+                    instance.check_status = check_status
+                    instance.check_comment = check_comment
+                    instance.check_time = timezone.now()
+                    instance.save()
+                    instance.customer.status = NewCustomer.ABANDONED
+                    # 如果客户已下单,把工单状态改成放弃
+                    Order.objects.filter(customer=instance.customer).update(status=Order.ABANDONED)
+                instance.customer.next_time = next_time
+                instance.customer.save()
+                NewCustomerRemind.objects.filter(customer=instance.customer, remind_user=instance.customer.track_user).update(next_time=next_time)
         except CustomError as e:
             return response_error(e.get_error_msg())
         except Exception as e:

+ 1 - 1
apps/order/models.py

@@ -44,7 +44,7 @@ class Order(models.Model):
 
     def get_no(self):
         now = timezone.now()
-        no = '%s%d-%s' % ('DD', self.service_user.id, now.strftime('%Y%m%d%H%M%S'))
+        no = '%s%d-%s' % ('DD', self.store.id, now.strftime('%Y%m%d%H%M%S'))
         return no
 
     @staticmethod

+ 46 - 10
apps/order/views.py

@@ -3,28 +3,29 @@ import traceback
 from rest_framework.views import APIView
 from rest_framework.decorators import action
 from django.db import transaction
-from django.conf import settings
-
+import datetime
+from django.utils import timezone
 from utils.custom_modelviewset import CustomModelViewSet
 from utils.exceptions import CustomError
-from .serializers import OrderSerializer,ProgressDetailsSerializer
+from .serializers import OrderSerializer, ProgressDetailsSerializer
 from .filters import OrderFilter
 from apps.log.models import BizLog
 from django.db.models import Q
 from utils import response_ok, response_error
 from utils.permission import isLogin, check_permission
-from apps.customer.models import NewCustomer
-from apps.order.models import Order,ProgressDetails
+from apps.customer.models import NewCustomer, NewCustomerRemind
+from apps.order.models import Order, ProgressDetails
 from apps.option.models import Option
 from apps.upload.models import Upload
 from apps.upload.serializers import UploadSerializer
 
+
 class GetProcessView(APIView):
     permission_classes = [isLogin]
 
     def get(self, request):
         customer_id = request.query_params.get('customer_id')
-        dispatch = request.query_params.get('dispatch') # 分配服务人员,
+        dispatch = request.query_params.get('dispatch')  # 分配服务人员,
 
         instance = NewCustomer.objects.filter(id=customer_id).first()
         if not instance:
@@ -44,9 +45,9 @@ class GetProcessView(APIView):
                                        enable=True).order_by('sort').first()
         if option:
             data = {
-                'now_process_text':instance.stage_progress.name,
-                'next_process_text':option.name,
-                'next_process_id':option.id,
+                'now_process_text': instance.stage_progress.name,
+                'next_process_text': option.name,
+                'next_process_id': option.id,
             }
             return response_ok(data)
         else:
@@ -76,6 +77,41 @@ class OrderViewSet(CustomModelViewSet):
             return None
         return self.paginator.paginate_queryset(queryset, self.request, view=self)
 
+    @action(methods=['post'], detail=True)
+    def dispatch_service(self, request, pk):
+        # 订单分配服务人员
+        check_permission(request, 'order.order_process_dispatch')
+        stage_progress = request.POST.get('stage_progress')
+        service = request.POST.get('service')
+
+        try:
+            with transaction.atomic():
+                stage_progress = Option.objects.filter(id=stage_progress, enable=True).order_by('sort').first()
+                if not stage_progress:
+                    raise CustomError('阶段进度有误,请刷新重试!')
+                if not stage_progress.track_day:
+                    raise CustomError('下一阶段进度,没有可用跟踪天数,请联系管理员设置!')
+                Order.objects.filter(id=pk).update(stage_progress=stage_progress, service_user_id=service,
+                                                   status=Order.NORMAL)
+
+                next_time = (timezone.now() + datetime.timedelta(days=stage_progress.track_day)).strftime('%Y-%m-%d')
+                # 更新进度,删除上一个跟踪人提醒
+                order = self.get_object()
+                NewCustomerRemind.objects.filter(customer=order.customer, remind_user=order.customer.track_user).delete()
+                NewCustomer.objects.filter(id=order.customer_id).update(
+                    stage_progress=stage_progress,
+                    track_user_id=service,
+                    next_time=next_time,
+                )
+                NewCustomerRemind.objects.create(customer=order.customer, remind_user_id=service, next_time=next_time)
+                operation = u'分配服务人员为:{}'.format(order.service_user.name)
+                ProgressDetails.objects.create(order=order, user=request.user, operation=operation,)
+        except CustomError as e:
+            return response_error(e.get_error_msg())
+        except Exception as e:
+            return response_error(str(e))
+        return response_ok()
+
 
 class GetDetailsView(APIView):
     permission_classes = [isLogin]
@@ -96,4 +132,4 @@ class GetFilesView(APIView):
         id = request.GET.get('id')
         images = Upload.objects.filter(progress_details_id=id)
         img_data = UploadSerializer(images, many=True).data
-        return response_ok(img_data)
+        return response_ok(img_data)

+ 0 - 1
uis/views/account/login.html

@@ -94,7 +94,6 @@
         ,data: {token: layui.data(setter.tableName)[setter.request.tokenName].substr(4)}
         ,type: 'post'
         ,done: function(res){
-
           //请求成功后,写入 access_token
           layui.data(setter.tableName, {
             key: setter.request.tokenName

+ 4 - 4
uis/views/employee/manage_range.html

@@ -58,20 +58,20 @@
         });
 
         form.on('submit(component-form-element)', function (data) {
-            var sotres = []
+            var stores = []
             for (var key in data.field) {
 
                 if (key.indexOf('store') > -1) {
-                    sotres.push(data.field[key])
+                    stores.push(data.field[key])
                 }
             }
-            if (sotres.length === 0) {
+            if (stores.length === 0) {
                 layer.msg('请选择门店');
                 return false;
             }
             admin.req({
                 url: '/account/employee/' + id + '/branch/'
-                , data: {sotres:JSON.stringify(sotres)}
+                , data: {stores:JSON.stringify(stores)}
                 , type: 'post'
                 , done: function (res) {
                     parent.layer.closeAll('iframe');

+ 2 - 2
uis/views/index.html

@@ -113,10 +113,10 @@
                           <cite>订单作业</cite>
                       </a>
                       <dl class="layui-nav-child">
-                          <dd data-name="nav" data-permission="customer.view_report_customer">
+                          <dd data-name="nav" data-permission="order.view_order">
                               <a lay-href="order/index.html">订单管理</a>
                           </dd>
-                          <dd data-name="nav" data-permission="customer.view_report_customer">
+                          <dd data-name="nav" data-permission="order.order_process_dispatch">
                               <a lay-href="order/dispatch_process_index.html">进度分配</a>
                           </dd>
                       </dl>

+ 2 - 2
uis/views/order/detail.html

@@ -103,10 +103,10 @@
             elem: '#customer_datagrid'
             , url: '/order/get_details/?order_id=' + order_id
             , cols: [[
-                {field: 'operation', title: "操作", width: 200}
+                {field: 'operation', title: "操作", width: 280}
                 , {field: 'operation_time_f', title: '操作时间', width: 150}
                 , {field: 'notes', title: '备注', width: 200}
-                , {field: 'user_text', title: '操作人', width: 120}
+                , {field: 'user_text', title: '操作人', width: 150}
                 , {width: 100, align: 'center', fixed: 'right', toolbar: '#customer-operate-bar'}
             ]]
             , page: true

+ 16 - 2
uis/views/order/dispatch_process_edit.html

@@ -110,7 +110,7 @@
             , form = layui.form;
 
         var customer_id = layui.view.getParameterByName('customer_id');
-        //form.render(null, 'component-form-element');
+        var order_id = layui.view.getParameterByName('order_id');
         var next_process_id = '';
         admin.req({
             url: '/order/get_process/?customer_id=' + customer_id + '&dispatch=1'
@@ -138,6 +138,19 @@
             }
         });
 
+        admin.req({
+            url: '/customer/get_user/',
+            done: function (res) {
+                var data_user = res.data;
+                var user_node = $('#id_service');
+                for (var i in data_user) {
+                    var pid = data_user[i].value;
+                    var name = data_user[i].lable;
+                    user_node.append("<option value='" + pid + "'>" + name + "</option>");
+                }
+                form.render()
+            }
+        });
 
         form.on('submit(component-form-element)', function (data) {
             var submitData = data.field;
@@ -145,7 +158,8 @@
                 layer.msg("下个进度阶段有误,请刷新重试!", {icon: 2});
                 return false
             }
-            var url = '/customer/new_customer/' + customer_id + '/add_order/';
+            submitData['stage_progress'] = next_process_id
+            var url = '/order/' + order_id + '/dispatch_service/';
             admin.req({
                 url: url
                 , data: submitData

+ 9 - 11
uis/views/order/dispatch_process_index.html

@@ -118,7 +118,8 @@
 
         table.render({
             elem: '#dispatch_process_datagrid'
-            , url: '/order/'
+            , url: '/order/?status=3'
+            , title: '订单管理'
             , cols: [[
                 {field: 'no', title: '单号', width: 180}
                 , {field: 'name', title: '客户名称', width: 110}
@@ -126,8 +127,8 @@
                 , {field: 'address', title: '地址', width: 200}
                 , {field: 'village', title: '小区', width: 200}
                 , {field: 'project_text', title: '项目', width: 120}
-                , {field: 'current_follow_user', title: '当前跟踪人', width: 100}
-                , {field: 'apply_process', title: "申请进度", width: 150}
+                , {field: 'stage_progress_text', title: "申请进度", width: 150}
+                , {field: 'service_user_text', title: '当前服务人', width: 150}
                 , {width: 150, align: 'center', fixed: 'right', toolbar: '#order-operate-bar'}
             ]]
             , page: true
@@ -150,25 +151,22 @@
                layer.open({
                 type: 2,
                 title: '查看详情',
-                area: ['45%', '80%'],
-                btn: ['取消'],
+                area: ['55%', '80%'],
+                btn: ['关闭'],
                 btn1: function (index, layero) {
                     layer.close(index);//关闭当前按钮
                 },
-                content: 'detail.html?id=' + data.id
+                content: 'detail.html?order_id=' + data.id
             });
             }else if(obj.event === "order_update"){
                 // 更新进度
                 layer.open({
                     type: 2,
                     title: '分配',
-                    area: ['30%', '45%'],
+                    area: ['40%', '55%'],
                     btn: ['保存','取消'],
                     yes: function (index, dom) {
                         layui.onSubmitChild = function (res) {
-                            if (res.code === 0) {
-                                layer.msg('分配成功!', {icon: 1})
-                            }
                             layer.close(index);
                             table.reload('dispatch_process_datagrid', {});
                         };
@@ -177,7 +175,7 @@
                     btn2: function (index, layero) {
                         layer.close(index);//关闭当前按钮
                     },
-                    content: 'dispatch_process_edit.html?customer_id=' + data.id
+                    content: 'dispatch_process_edit.html?customer_id=' + data.customer +'&order_id=' + data.id
                 });
             }
         });

+ 1 - 1
uis/views/order/imgsInfo.html

@@ -64,7 +64,7 @@
             , cols: [[
                 {field: 'create_time_f', title: "上传时间", width: 220}
                 , {field: 'file_size', title: '文件大小', width: 120}
-                , {field: 'user_text', title: '上传人', width: 120}
+                , {field: 'user_text', title: '上传人', width: 150}
                 , {width: 80, align: 'center', fixed: 'right', toolbar: '#customer-imgs-operate-bar'}
             ]]
         });

+ 1 - 1
uis/views/order/index.html

@@ -175,7 +175,7 @@
                 type: 2,
                 title: '查看详情',
                 area: ['55%', '80%'],
-                btn: ['取消'],
+                btn: ['关闭'],
                 btn1: function (index, layero) {
                     layer.close(index);//关闭当前按钮
                 },

+ 1 - 1
uis/views/report_check/divide.html

@@ -31,7 +31,7 @@
                 <form class="layui-form" action="" lay-filter="component-form-element">
                     <div class="layui-row layui-col-space10 layui-form-item">
                         <div>
-                            <label class="layui-form-label"><font color='red' size="4">*</font>选择人员:</label>
+                            <label class="layui-form-label"><font color='red' size="4">*</font>选择客户经理:</label>
                             <div class="layui-input-block">
                                 <select lay-verify="required" name="user" id="id_user">
                                     <option value="">请选择人员</option>

+ 3 - 2
utils/__init__.py

@@ -1,5 +1,5 @@
 #coding=utf-8
-
+import traceback
 from rest_framework import status
 from rest_framework.response import Response
 
@@ -7,6 +7,7 @@ def response_error(msg, errcode=None):
     code = 1
     if errcode:
         code = errcode
+    traceback.print_exc()
     return Response({"code":code, "msg": msg}, status=status.HTTP_200_OK)
 
 def response_ok(data=None):
@@ -21,4 +22,4 @@ def get_remote_addr(request):
         ip = x_forwarded_for.split(',')[0]
     else:
         ip = request.META.get('REMOTE_ADDR')
-    return ip
+    return ip